The $group stage in MongoDB is used to group documents
according to a specified field or expression. It allows us to
calculate totals, averages, counts, maximum values, and minimum
values for each group.
The $group stage combines documents that have
the same grouping key and produces one output document
for each group.
Common uses include:
Basic syntax:
db.collection.aggregate([
{
$group: {
_id: "$fieldName",
resultField: { $sum: "$numericField" }
}
}
])
The _id field specifies the grouping key.
It is required in a $group stage, but its
value can be null when all documents should
belong to one group.
Use the following sample student records:
use school
db.group_students.insertMany([
{ name: "Rahul", course: "Java", fees: 5000, marks: 85 },
{ name: "Priya", course: "Python", fees: 6000, marks: 90 },
{ name: "Aman", course: "Java", fees: 4500, marks: 75 },
{ name: "Neha", course: "Python", fees: 5500, marks: 88 },
{ name: "Ravi", course: "Java", fees: 4000, marks: 80 },
{ name: "Anjali", course: "Web Development", fees: 7000, marks: 92 }
])
Note: Run insertMany() only
once for this sample. Re-running it inserts duplicate
records with new automatically generated IDs.
Use _id: "$course" to group students according
to their course.
db.group_students.aggregate([
{
$group: {
_id: "$course"
}
}
])
Example result:
[
{ _id: "Java" },
{ _id: "Python" },
{ _id: "Web Development" }
]
Each distinct course produces one output document. The order of these groups is not guaranteed.
Use { $sum: 1 } to count the documents
belonging to each group.
db.group_students.aggregate([
{
$group: {
_id: "$course",
totalStudents: { $sum: 1 }
}
}
])
Example result:
[
{ _id: "Java", totalStudents: 3 },
{ _id: "Python", totalStudents: 2 },
{ _id: "Web Development", totalStudents: 1 }
]
Here, $sum: 1 adds one for every document
in each course group.
Use $sum with the fees field to calculate
the total fees for each course.
db.group_students.aggregate([
{
$group: {
_id: "$course",
totalFees: { $sum: "$fees" }
}
}
])
Example result:
[
{ _id: "Java", totalFees: 13500 },
{ _id: "Python", totalFees: 11500 },
{ _id: "Web Development", totalFees: 7000 }
]
The Java total is ₹13,500 because ₹5,000 + ₹4,500 + ₹4,000 = ₹13,500.
The $avg accumulator calculates the average
of numeric values in each group.
db.group_students.aggregate([
{
$group: {
_id: "$course",
averageMarks: { $avg: "$marks" }
}
}
])
Example result:
[
{ _id: "Java", averageMarks: 80 },
{ _id: "Python", averageMarks: 89 },
{ _id: "Web Development", averageMarks: 92 }
]
Java's average is calculated as (85 + 75 + 80) / 3 = 80.
MongoDB provides $max and $min
accumulators to find the highest and lowest numeric
values within each group.
db.group_students.aggregate([
{
$group: {
_id: "$course",
highestMarks: { $max: "$marks" },
lowestMarks: { $min: "$marks" }
}
}
])
Example result:
[
{ _id: "Java", highestMarks: 85, lowestMarks: 75 },
{ _id: "Python", highestMarks: 90, lowestMarks: 88 },
{ _id: "Web Development", highestMarks: 92, lowestMarks: 92 }
]
Set _id: null when you want to calculate
a result for the entire collection rather than separate
groups.
db.group_students.aggregate([
{
$group: {
_id: null,
totalStudents: { $sum: 1 },
totalFees: { $sum: "$fees" },
averageMarks: { $avg: "$marks" },
highestMarks: { $max: "$marks" },
lowestMarks: { $min: "$marks" }
}
}
])
Expected result for the sample data:
[
{
_id: null,
totalStudents: 6,
totalFees: 32000,
averageMarks: 85,
highestMarks: 92,
lowestMarks: 75
}
]
You can group documents by more than one field by using
an embedded document as the value of _id.
For example, suppose student records also have a city field.
db.group_students.aggregate([
{
$group: {
_id: {
course: "$course",
marks: "$marks"
},
totalStudents: { $sum: 1 }
}
}
])
This groups documents by the combination of course and marks. Students are placed in the same group only when both grouping values match.
To group by course and city instead, use
course: "$course" and
city: "$city" in the grouping key.
A city field must exist in your data for that example
to produce meaningful city groups.
Multiple aggregation stages can be combined into one pipeline. This example selects students with marks of at least 80, groups them by course, and sorts courses by student count.
db.group_students.aggregate([
{
$match: {
marks: { $gte: 80 }
}
},
{
$group: {
_id: "$course",
totalStudents: { $sum: 1 },
totalFees: { $sum: "$fees" },
averageMarks: { $avg: "$marks" }
}
},
{
$sort: {
totalStudents: -1,
_id: 1
}
}
])
Understand the pipeline:
$match filters students with marks of at least 80.$group calculates totals and averages for each course.$sort sorts by student count in descending order, then by course name in ascending order for ties.
Use the group_students collection to solve
these exercises:
1. Which stage groups documents in an aggregation pipeline?
2. Which accumulator counts documents in each group when used as shown?
3. What does _id: null do in a $group stage?