You need to conditionally determine the grouping key based on where the current date falls in between the range. This is basically achieved via $cond
with nested condtions and the logical variant of $lt
:
// work out dates somehow
var today = new Date(),
oneDay = ( 1000 * 60 * 60 * 24 ),
thirtyDays = new Date( today.valueOf() - ( 30 * oneDay ) ),
fifteenDays = new Date( today.valueOf() - ( 15 * oneDay ) ),
sevenDays = new Date( today.valueOf() - ( 7 * oneDay ) );
db.collection.aggregate([
{ "$match": {
"date": { "$gte": thirtyDays }
}},
{ "$group": {
"_id": {
"$cond": [
{ "$lt": [ "$date", fifteenDays ] },
"16-30",
{ "$cond": [
{ "$lt": [ "$date", sevenDays ] },
"08-15",
"01-07"
]}
]
},
"count": { "$sum": 1 },
"totalValue": { "$sum": "$value" }
}}
])
As $cond
is a ternary operator, the first condition is evaluated to see if the condition is true, and when true the second argument is returned otherwise the third is returned when false. So by nesting another $cond
in the false case you get the logical test on where the date falls, either "less that the 15 day date" which means its in the oldest range, or "less than 7 days" which means the middle range, or of course it's in the newest range.
I'm just prefixing the numbers here less than 10 with a 0
so it gives you something to sort on if you want, since the output of "keys" in $group
is not in itself ordered.
But that is how you do this in a single query. You just work out what the grouping key should be based on where the date falls and accumulate for each key.
$cond
are actually for. – Gezira