2016-08-18 74 views
3

我的文件看起來是這樣的:集團首先通過類別,然後按周或按月

{ 
    category: "1", 
    timestamp: ISODate("2016-07-16T00:00:00.000Z"), 
    amount: 0 
}, 
{ 
    category: "1", 
    timestamp: ISODate("2016-08-18T00:00:00.000Z"), 
    amount: 15 
}, 
{ 
    category: "1", 
    timestamp: ISODate("2016-08-01T00:00:00.000Z"), 
    amount: 5 
}, 
{ 
    category: "2", 
    timestamp: ISODate("2016-08-18T00:00:00.000Z"), 
    amount: 10 
} 

現在我想第一組按類別(已工作):

{ "$match" : { "timestamp" : { "$gt" : FROM , "$lt" : TO }}}, 
{ "$sort" : { "timestamp" : 1 }}, 
{ "$group" : { 
    "_id" : "$category", 
    "data" : { "$push" : { "timestamp" : "$timestamp" , "amount" : "$amount" }} 
}} 

然後將這些對象分組在data陣列中。要獲得每週最高金額(或月 - 取決於用戶輸入)。

然後結果應該是這個樣子(按月分組時):

{ 
    _id: "1", 
    data: [ 
     { 
      timestamp: "2016-07", // could also be an ISODate with 
      amount: 0    // first (or last) day of month 
     },       // if that makes things easier 
     { 
      timestamp: "2016-08", 
      amount: 15 
     } 
    ] 
}, 
{ 
    _id: "2", 
    data: [ 
     { 
      timestamp: "2016-08", 
      amount: 10 
     } 
    ] 
} 

我試圖unwinddata數組,然後再分組,但導致總共爛攤子。

希望你有一些很好的想法/解決方案來實現這個工作。

編輯:另一個問題:

我穿上category這只是正常的$match的索引。將timestamp作爲排序索引也是有用的(因爲插入排序可能與時間戳排序有所不同),還是這個索引在聚合中不起作用?

回答

2

我已經採取了Styvane的答案(再次感謝!),並簡化了一點:

{$match: { timestamp: { $gt: FROM , $lt: TO }}}, 
{$group: { 
    _id: { 
     id: "$category", 
     timestamp: { $concat: [ 
      { $toLower: { $year:"$timestamp" } }, 
      "-", 
      { $toLower: { $month: "$timestamp" } } 
     ] } 
    }, 
    amount: { $max: "$amount" } 
}}, 
{$sort: { "_id.timestamp": 1 } }, 
{$group: { 
    _id: "$_id.id", 
    data: { $push: { timestamp: "$_id.timestamp", amount: "$amount" } } 
}} 

我試圖$sort第一$group之前,但這並給出有時會出現意想不到的結果。雖然我只是把$sort放在$group階段之間。這種方式有timestamp索引不再關係。

1

$sort階段之後,您需要通過「類別」$group然後$unwind「數據」字段。

var group1 = { "$group": { 
    "_id": "$category", 
    "data": { 
     "$push": { 
      "timestamp": "$timestamp", 
      "amount": "$amount" 
     } 
    } 
}}; 

var unwind = { "$unwind": "$data"}; 

從那裏,你需要重新$group您的文檔,但你需要考慮的不僅是timestamp場,但_id領域以及這個時間,與$toLower運營商的幫助下,你可以轉換的一年字符串的月份值,您可以使用$concat運算符進行連接。

您還返回該組的總和$sum

var group2 = { "$group": { 
    "_id": { 
     "id": "$_id", 
     "timestamp": { 
      "$concat": [ 
       { "$toLower": { "$year": "$data.timestamp" } }, 
       "-", 
       { "$toLower": { "$month": "$data.timestamp" } } 
      ] 
    }}, 
    "amount": { "$sum": "$data.amount" } 
}} 

最後一個階段是另一個$group階段,你只需小組您先前_id.id價值票據和使用$push累加器操作返回數據的數組。

var group3 = { "$group": { 
    "_id": "$_id.id", 
    "data": { 
     "$push": { 
      "timestamp": "$_id.timestamp", 
      "amount": "$amount" 
     } 
    } 
}}; 

您的最終管道將是這樣的:

db.collection.aggregate(
    [ 
     // $match and `$sort here 
     group1, 
     unwind, 
     group2, 
     group3 
    ] 
) 

這種查詢可以在MongoDB中的即將推出的版本可以提高使用$facet操作。

db.collection.aggregate([ 
    // $match and `$sort here 
    { "$facet": { "data": [ group1, unwind, group2, group3 ] } 
]) 
+0

哇!謝謝!我稍後會經過並嘗試。你有什麼意見在時間戳字段上創建索引進行排序? –

+0

我根據您的代碼添加了自己的答案。它對集合本身進行分組,雖然不需要'group1'和'unwind'。但是現在'$ match'後面的'$ sort'沒有給出預期的結果。我無法解釋這種情況。儘管我在'$ group'階段之間放置了'$ sort'。 –