I’m trying to show the top customers in the last 24 hours and last 12 hours using one DB Query.
We save the total orders of the customer in the db every one hour.
The raw data are something like the below, but i changed with the data for confidentiality:
[
{
"_id": ObjectId("64c8de6e10f1e5f6958033d7"),
"address": "nowhere",
"city": "NY",
"name": "ABD",
"count": NumberInt(19),
"timestamp": ISODate("2023-08-01T05:30:42.956Z")
},
{
"_id": ObjectId("64c8de6e10f1e5f6958033d6"),
"address": "somewhere",
"city": "NY",
"name": "WBE",
"count": NumberInt(4),
"timestamp": ISODate("2023-08-01T05:29:02.956Z")
},
{
"_id": ObjectId("64c8de6e10f1e5f6958033da"),
"address": "somewhere",
"city": "NY",
"name": "WBE",
"count": NumberInt(18),
"timestamp": ISODate("2023-08-01T08:30:42.956Z")
}
...
]
The result i was trying to go for was something like:
{
last12Hours: [{ name: "WBE", city:"NY", count: "18" }, {name: "ABD", city:"NY", count: "12"}],
last24Hours: [{ name: "WBE", city:"NY", count: "30" }, {name: "ABD", city:"NY", count: "20"}],
}
This is simple if i run two queries where i change the timestamp match to 12 hours before and 24 hours before:
db.collection.aggregate([
{
$match: {
timestamp: {
$gte: ISODate("2023-08-01T03:36:38.059Z")
},
},
},
{
$group: {
_id: "$name",
count: {
$sum: "$count"
},
city: { $first: "$city"}
},
},
{
$sort: {
count: -1
}
},
{
$limit: 5,
},
{
$project: {
_id: 0,
name: "$_id",
city: "$city",
count: 1,
},
},
])
I also tried something that has to do with intervals but that was a disaster of a query and didn’t work as expected.
I apprecaite hints, im not supposidly asking for anyone to just solve it. Thank you!
2
Answers
For your scenario, you need the
$facet
stage to execute multiple aggregation pipelines within a single stage and result in a single document.Unsure what is your
last12HoursTimestamp
andlast24HoursTimestamp
, your query should be as below:Demo @ Mongo Playground
Bonus: Besides passing the timestamp, you may use the MongoDB operator & function to calculate the timestamps for the last 12 & 24 hours as well.
Since
$facet
is not using indexes, you may want to use it as late as possible in your pipeline. Another option, following @YongShun, is to$match
and$group
before the$facet
using$cond
. This will allow you to use the index on these stages, and enter the$facet
stage with less documents:See how it works on the playground example