Jest to raczej kwestia tego, jak oczekujesz wyniku, ponieważ każdy zagregowany wynik zasadniczo musi być grupowany na najniższym poziomie, a następnie stopniowo grupowany na wyższych „ziarnach” aż do osiągnięcia najwyższego poziomu („miesiąc”). Ten rodzaj oznacza dane pogrupowane według „miesiąca”, chyba że podzielisz je w inny sposób.
Zasadniczo stopniowo $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" }
}}
])
Tak więc każdy poziom po pierwszym, który sumuje się na dzień, jest stopniowo umieszczany w zawartości tablicy ze względu na swoją wartość „zaokrągloną w górę”, a sumy są następnie sumowane również na tym poziomie.
Jeśli chcesz uzyskać bardziej płaskie dane wyjściowe z jednym rekordem dziennie zawierającym sumy tygodniowe i miesięczne, a także sumę dniową, po prostu dołącz dwa $unwind
oświadczenia do końca potoku:
{ "$unwind": "$weeks" },
{ "$unwind": "$weeks.days" }
I opcjonalnie $project
"kropkowane" pola są bardziej płaskie i czytelne, jeśli musisz.
Jeśli obejmujesz tym "lata", uwzględnij taką operację w kluczu grupującym przynajmniej z poziomu "tydzień", aby nie łączyć danych z różnych lat i są one rozdzielone.
Preferuję również używanie "matematyka dat"
podejście podczas zaokrąglania dat, ponieważ zwraca Date
obiekt, ale tak jak jest używany na innych poziomach niż „dzień”, możesz po prostu naprzemiennie użyć operatory agregacji dat
zamiast tego.
Nie ma potrzeby stosowania mapReduce
ponieważ jest to dość intuicyjne i istnieje skończona liczba dni w miesiącu, co oznacza, że limit BSON podczas zagnieżdżania tablic w treści podczas agregacji nie zostanie złamany.