Skip to content

Aggregation Expressions

Date Expressions

$year, $month, $dayOfMonth and $dateToString for grouping and display.

IntermediateAbout 5 minutes

BSON dates are UTC instants. Reports want calendar buckets: month, day, YYYY-MM. Extract parts, or format a string, then $group on that. Do not $group on the raw createdAt unless you meant exact milliseconds.

db.orders.aggregate([
  {
    $group: {
      _id: { year: { $year: "$createdAt" }, month: { $month: "$createdAt" } },
      revenue: { $sum: "$amount" }
    }
  }
])
Parts for a compound _id
db.orders.aggregate([
  { $match: { status: { $in: ["shipped", "delivered"] } } },
  {
    $group: {
      _id: { $dateToString: { format: "%Y-%m", date: "$createdAt" } },
      revenue: { $sum: "$amount" },
      orders: { $sum: 1 }
    }
  },
  { $sort: { _id: 1 } }
])
The practice shape — one sortable string
{ _id: "2026-07", revenue: 210000, orders: 40 }
{ _id: "2026-08", revenue: 185000, orders: 36 }
OperatorUse
$year / $month / $dayOfMonthNumeric parts; $dayOfWeek is 1=Sunday
$dateToStringformat: %Y-%m-%d, %H, timezone: "Asia/Kolkata"
$dateTrunc5.0+: { unit: "month" } — cleaner than a string if you can use it

timezone on $dateToString / $year is how Bangalore's 12:30 AM on the 1st does not fall in the previous UTC day. Omit it and you group in UTC. $add milliseconds to a date is duration; $dateAdd / $dateDiff (5.0) are the readable form. Filter status with $match before you group by month — cancelled orders do not belong in revenue.

Interview question

How do you group documents by calendar month in MongoDB?

Think about it first.

Practice

Filter statuses, then group on a YYYY-MM string.