2016-08-18 12 views
3

マイドキュメントは、次のようになりますグループは、最初のカテゴリで、その後、週または月で

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

{ 
    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 
} 

私が(すでに動作します)カテゴリー別最初のグループが欲しいです

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 
     } 
    ] 
} 

私はdata配列をunwindしようとしたし、再度グループ化するが、それは総混乱が生じました。

希望のアイデアや解決方法がありますようお願いいたします。

EDIT:追加の質問:

私は$matchのためだけで正常に動作categoryにインデックスを入れています。並べ替えのために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" } } 
}} 

私が最初$group$sortしようとしたが、その場合、予期しない結果が得られました。私はちょうどを$groupのステージの間に置いた。 timestampにインデックスを持つこの方法は、もはや重要ではありません。

1

$sortステージの後には、 "カテゴリ"で$group、次に "データ"フィールドで$unwindが必要です。そこから

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

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

、あなたは$groupドキュメントを再度する必要があるが、今回はあなたにも、あなたが今年変換することができます$toLowerオペレータの助けを借りてtimestampフィールドが、_idフィールドだけでなく、検討する必要があると$concat演算子を使用して連結できる文字列の月の値。

また、$sumでそのグループの合計を返します。

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

最終ステージは前回_id.id値によって、あなたは、単にグループドキュメント別$groupの段階であり、データの配列を返すように$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 
    ] 
) 

このクエリは$facet演算子を使用してのMongoDBの次期バージョンで改善することができます。

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

うわー!ありがとうございました!私は後でそれを試してみよう。並べ替えのためにタイムスタンプフィールドにインデックスを作成する意見はありますか? –

+0

私は自分のコードに基づいて独自の答えを追加しました。 'group1'と' unwind'は必要ありませんが、コレクション自体をグループ化します。しかし、 '$ match'の直後の' $ sort'は期待された結果を得られませんでした。私はこれを説明することはできません。私は '$ sort'を' $ group'の段階の間に置いています。 –

関連する問題