Dette er mere virkelig et spørgsmål om, hvordan du forventer, at output skal se ud, da ethvert aggregeret resultat i det væsentlige skal grupperes på det laveste niveau og derefter gradvist grupperes ved højere "korn", indtil det største niveau ("måned") er nået. Denne form for indebærer data grupperet efter "måned" i sidste ende, medmindre du opdeler dem på anden måde.
I det væsentlige, gradvist $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" }
}}
])
Så hvert niveau efter det første, som opsummerer pr. dag, skubbes derefter gradvist ind i matrixindholdet for dets "runde op"-værdi, og totalerne summeres derefter også på det niveau.
Hvis du vil have et fladere output med én post pr. dag, der indeholder dets ugentlige og månedlige totaler samt det samlede antal dage, skal du blot tilføje to $unwind
udsagn til slutningen af pipelinen:
{ "$unwind": "$weeks" },
{ "$unwind": "$weeks.days" }
Og eventuelt $project
de "prikkede" felter ud til noget fladere og læsbart, hvis du skal.
Hvis du spænder over "år" med dette, så inkluder en sådan operation i grupperingsnøglen i det mindste fra "uge"-niveauet, så du muligvis ikke kombinerer data fra forskellige år, og de er adskilt.
Det er også min egen generelle præference at bruge "date math"
tilgang ved afrunding af datoer, da den returnerer en Date
objekt, men som det bruges på de andre niveauer end "dag", kan du bare skiftevis bruge datoaggregationsoperatører
i stedet.
Intet behov for mapReduce
da dette er ret intuitivt, og der er et begrænset antal dage i en måned, betyder det, at BSON-grænsen, når indlejring af arrays i indholdet, mens aggregering ikke vil blive brudt.