集約された結果は基本的に最低レベルでグループ化し、次に最大レベル(「月」)に達するまで徐々に高い「粒度」でグループ化する必要があるため、これは実際には出力がどのように見えるかという問題です。この種のデータは、別の方法で分類しない限り、最終的に「月」でグループ化されたデータを意味します。
本質的には、徐々に $group
:
db.collection.aggregate([
// First total per day. Rounding dates with math here
{ "$group": {
"_id": {
"$add": [
{ "$subtract": [
{ "$subtract": [ "$createdAt", new Date(0) ] },
{ "$mod": [
{ "$subtract": [ "$createdAt", new Date(0) ] },
1000 * 60 * 60 * 24
]}
]},
new Date(0)
]
},
"week": { "$first": { "$week": "$createdAt" } },
"month": { "$first": { "$month": "$createdAt" } },
"total": { "$sum": "$num" }
}},
// Then group by week
{ "$group": {
"_id": "$week",
"month": { "$first": "$month" },
"days": {
"$push": {
"day": "$_id",
"total": "$total"
}
},
"total": { "$sum": "$total" }
}},
// Then group by month
{ "$group": {
"_id": "$month",
"weeks": {
"$push": {
"week": "$_id",
"total": "$total",
"days": "$days"
}
},
"total": { "$sum": "$total" }
}}
])
したがって、1日あたりの合計が最初以降の各レベルは、「切り上げ」値の配列コンテンツに徐々にプッシュされ、合計もそのレベルで合計されます。
1日あたり1つのレコードで、週ごとと月ごとの合計、および日の合計を含む、よりフラットな出力が必要な場合は、2つの$unwind
を追加するだけです。 パイプラインの最後までのステートメント:
{ "$unwind": "$weeks" },
{ "$unwind": "$weeks.days" }
オプションで$project
「点線」のフィールドは、必要に応じて、よりフラットで読みやすいものになります。
これで「年」にまたがる場合は、少なくとも「週」レベルからグループ化キーにそのような操作を含めて、異なる年のデータを結合してそれらを分離しないようにします。
"datemath"
を使用することも私自身の一般的な好みです。 Date
を返すため、日付を丸めるときのアプローチ オブジェクトですが、「日」以外のレベルで使用されているように、日付集計演算子
代わりに。
mapReduce
は必要ありません これはかなり直感的であり、1か月の日数には限りがあるため、集計中にコンテンツに配列をネストする場合のBSONの制限は破られません。