Grouping by more than one field
Grouping by two fields is just an object as the _id. The part that catches people is the output: your grouping key is now nested inside _id, so every later stage has to reach through it.
Suppose:
Find quantity sold per user per product.
You can group by an object.
{
$group: {
_id: {
userId: "$userId",
product: "$items.product"
},
quantity: {
$sum: "$items.quantity"
}
}
}
Result:
{
_id: {
userId: 101,
product: "Laptop"
},
quantity: 1
}
This is equivalent conceptually to:
GROUP BY userId, product
The $group _id Is Just the Grouping Key
This confuses many people initially.
Here:
{
$group: {
_id: "$userId"
}
}
_id does not mean the original document ID.
Inside $group:
_idmeans “what am I grouping by?”
Examples:
_id: "$userId"
Group by user.
_id: "$items.product"
Group by product.
_id: null
Everything goes into one group.
Example:
{
$group: {
_id: null,
totalRevenue: {
$sum: "$amount"
}
}
}
Result:
{
_id: null,
totalRevenue: 50000
}
Meaning:
Calculate one total across all documents.
This is a common interview pattern.
Try it
db.orders.aggregate([
{ $unwind: "$items" },
{
$group: {
_id: {
userId: "$userId",
product: "$items.product"
},
quantity: { $sum: "$items.quantity" }
}
},
{ $sort: { quantity: -1 } },
{ $limit: 5 }
])
Look at the shape of _id in the output. If you wanted to sort by user next, the field is _id.userId, not userId - that is the cost of the compound key.