MongoDB $group Stage: Grouping Documents in Aggregation
Learn how MongoDB's $group aggregation stage groups documents by a field value, and how to combine it with $match to group only a filtered subset.
The $group Stage
$group is where MongoDB aggregation starts feeling like SQL's GROUP BY. It collapses documents that share the same value for a chosen field into a single output document per group.
Syntax
db.collection.aggregate([
{ $match: { field: value } }, // optional
{ $group: { _id: "$field" } }
])
Grouping by a Field
db.employees.aggregate([
{ $group: { _id: "$city" } }
])
// {_id: 'Palghar'}
// {_id: 'Mumbai'}
// {_id: 'Pune'}
This is essentially distinct("city"), but expressed as a pipeline — and it becomes far more powerful once you add accumulators (covered in the next lesson).
db.employees.aggregate([
{ $group: { _id: "$reportinmgr.mgrid" } }
])
// grouping also works on embedded fields
Counting Documents Per Group
Add an accumulator field alongside _id to compute something for each group — $sum: 1 counts how many documents fell into each one:
db.employees.aggregate([
{ $group: { _id: "$city", countcity: { $sum: 1 } } }
])
// { _id: 'Mumbai', countcity: 3 }
// { _id: 'Pune', countcity: 3 }
// { _id: 'Palghar', countcity: 3 }
Advertisement728 x 90
Grouping a Filtered Subset
Add $match before $group to only group documents that meet a condition first:
db.employees.aggregate([
{ $match: { salary: { $gte: 50000 } } },
{ $group: { _id: "$city" } }
])
Common Errors & Troubleshooting
- Confusing
$group's_idwith the document's real_id— inside a$groupstage,_idrefers to the grouping key you chose, not the original document identifier — the original_idfield is not carried through unless you explicitly collect it with$push/$first. - Grouping on a field that doesn't exist in some documents — documents missing the grouping field get grouped together under
_id: null, which can silently merge unrelated "missing data" documents into one bucket. - Expecting
$groupto preserve document order — without a$sortbefore it,$groupdoesn't guarantee which document's values end up in$first/$last— always$sortfirst if the "first"/"last" document matters.
Key Takeaways
$group's_iddefines what counts as "the same group" — don't confuse it with each document's original_id.- Without an accumulator,
$groupbehaves likedistinct(). - Put
$matchbefore$groupwhen you only want to summarize a subset of the collection.
Advertisement320 x 100