Grouping by date
Reporting questions are almost always date questions - per day, per month, per year. There are two ways to group by date, and the choice between them is really a choice about what you want the output label to look like.
You will almost certainly encounter:
Group sales by month.
Suppose:
{
createdAt: ISODate("2026-01-15"),
amount: 500
}
You can group by year and month:
{
$group: {
_id: {
year: {
$year: "$createdAt"
},
month: {
$month: "$createdAt"
}
},
revenue: {
$sum: "$amount"
}
}
}
Result:
{
_id: {
year: 2026,
month: 1
},
revenue: 5000
}
$dateToString
Often cleaner for output:
{
$group: {
_id: {
$dateToString: {
format: "%Y-%m",
date: "$createdAt"
}
},
revenue: {
$sum: "$amount"
}
}
}
Result:
{
_id: "2026-01",
revenue: 5000
}
Then:
{
$sort: {
_id: 1
}
}
Try it
db.orders.aggregate([
{
$group: {
_id: {
year: { $year: "$createdAt" },
month: { $month: "$createdAt" }
},
orders: { $sum: 1 }
}
},
{ $sort: { "_id.year": 1, "_id.month": 1 } }
])
The label is an object, so sorting means reaching through _id. Try $dateToString instead and the label becomes "2025-11" - one string, sortable on its own.