Lesson 25 of 50 – Aggregation with $group
50%

Aggregation with $group in MongoDB

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.

1. What Is $group?

The $group stage combines documents that have the same grouping key and produces one output document for each group.

Common uses include:

  • Counting students in each course.
  • Calculating total fees for each course.
  • Finding average marks by course.
  • Finding the highest salary in each department.
  • Calculating the minimum and maximum product prices.

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.

2. Sample Data

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.

3. Group Documents by Course

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.

4. Count Documents Using $sum

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.

5. Calculate Total Fees by Course

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.

6. Calculate Average Marks Using $avg

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.

7. Find Maximum and Minimum Values

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 }
]

8. Group All Documents Together

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
    }
]

9. Group by Multiple Fields

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.

10. Combine $match, $group, and $sort

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:

  1. $match filters students with marks of at least 80.
  2. $group calculates totals and averages for each course.
  3. $sort sorts by student count in descending order, then by course name in ascending order for ties.

11. Practical Assignment

Use the group_students collection to solve these exercises:

  1. Count the students in each course.
  2. Calculate total fees collected for each course.
  3. Find the average marks for each course.
  4. Find the highest marks for each course.
  5. Find the lowest marks for each course.
  6. Calculate the total number of students in the collection.
  7. Calculate the total fees collected from all students.
  8. Display courses with an average mark of at least 85.
  9. Sort courses by total fees from highest to lowest.
  10. Calculate student count, total fees, and average marks by course in one pipeline.

🧠 Quick Quiz

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?