DocsHub
Aggregation

Aggregation Expressions

Learn how to use MongoDB aggregation expressions — $sum, $avg, $min, $max, $push, $addToSet, $concat, $toUpper, $toLower, and $dateToString.

Aggregation Expressions

Expressions are the building blocks of aggregation stages. You have already used some of them — $sum, $avg, $min, $max inside $group. But MongoDB has many more expressions for working with strings, dates, arrays, and arithmetic.

This file covers all the most important ones with real examples from our school system.


Where Expressions Are Used

Expressions appear inside stages like $group, $project, $addFields, and $match (with $expr). They always reference field values with a $ prefix:

"$fieldName"       // reference a field value
{ $sum: "$age" }   // expression using a field value
{ $add: ["$a", "$b"] }  // expression using two field values

Accumulator Expressions

These are used inside $group to calculate values across a group of documents.

$sum

Adds up values. Pass 1 to count documents, or "$fieldName" to sum a field:

db.students.aggregate([
  {
    $group: {
      _id: "$grade",
      totalStudents: { $sum: 1 },
      totalFees: { $sum: "$feesPaid" }
    }
  }
])

$avg

Calculates the average of a field across all documents in the group:

db.students.aggregate([
  {
    $group: {
      _id: "$grade",
      averageAge: { $avg: "$age" },
      averageScore: { $avg: "$examScore" }
    }
  }
])

$min and $max

Returns the smallest or largest value in the group:

db.students.aggregate([
  {
    $group: {
      _id: "$grade",
      youngestAge: { $min: "$age" },
      oldestAge: { $max: "$age" },
      lowestScore: { $min: "$examScore" },
      highestScore: { $max: "$examScore" }
    }
  }
])

$count

Counts the number of documents in a group. Available as a standalone stage or as an accumulator:

// As an accumulator in $group
db.students.aggregate([
  {
    $group: {
      _id: "$grade",
      total: { $count: {} }
    }
  }
])

// As a standalone stage — counts all documents passing through
db.students.aggregate([
  { $match: { enrolled: true } },
  { $count: "totalEnrolled" }
])

Result of the standalone $count:

[ { totalEnrolled: 124 } ]

$push

Collects all values in the group into an array:

// Collect all student names per grade into an array
db.students.aggregate([
  {
    $group: {
      _id: "$grade",
      studentNames: { $push: "$name" }
    }
  }
])

Result:

[
  {
    _id: "10th",
    studentNames: ["Ali Hassan", "Bilal Ahmed", "Sara Ahmed", ...]
  },
  {
    _id: "11th",
    studentNames: ["Umar Farooq", "Ayesha Khan", ...]
  }
]

You can push entire objects too:

// Collect student name and score pairs per grade
db.students.aggregate([
  {
    $group: {
      _id: "$grade",
      students: {
        $push: {
          name: "$name",
          score: "$examScore"
        }
      }
    }
  }
])

$addToSet

Like $push, but only adds unique values — duplicates are ignored:

// Collect unique cities where students live per grade
db.students.aggregate([
  {
    $group: {
      _id: "$grade",
      cities: { $addToSet: "$address.city" }
    }
  }
])

Result:

[
  { _id: "10th", cities: ["Lahore", "Karachi", "Islamabad"] },
  { _id: "11th", cities: ["Lahore", "Multan"] }
]

If ten students are from Lahore, $push adds "Lahore" ten times. $addToSet adds it only once.

$first and $last

Returns the first or last value in the group. Useful after sorting:

// For each grade — get the name of the top scoring student
db.students.aggregate([
  { $match: { enrolled: true } },
  { $sort: { examScore: -1 } },
  {
    $group: {
      _id: "$grade",
      topStudent: { $first: "$name" },
      topScore: { $first: "$examScore" },
      bottomStudent: { $last: "$name" },
      bottomScore: { $last: "$examScore" }
    }
  }
])

Result:

[
  { _id: "10th", topStudent: "Ali Hassan", topScore: 98, bottomStudent: "Bilal Ahmed", bottomScore: 42 },
  { _id: "11th", topStudent: "Ayesha Khan", topScore: 97, bottomStudent: "Umar Farooq", bottomScore: 51 }
]

Arithmetic Expressions

Used inside $project and $addFields to compute new values.

$add

Adds numbers or adds milliseconds to a date:

db.students.aggregate([
  {
    $project: {
      name: 1,
      nextYearAge: { $add: ["$age", 1] },
      totalScore: { $add: ["$examScore", "$assignmentScore"] }
    }
  }
])

$subtract

Subtracts one value from another:

db.students.aggregate([
  {
    $project: {
      name: 1,
      age: 1,
      birthYear: { $subtract: [2024, "$age"] },
      scoreDifference: { $subtract: ["$examScore", "$assignmentScore"] }
    }
  }
])

$multiply

Multiplies values:

// Calculate total fee with 10% late fee added
db.students.aggregate([
  {
    $project: {
      name: 1,
      baseFee: "$feesPaid",
      feeWithLatePenalty: { $multiply: ["$feesPaid", 1.10] }
    }
  }
])

$divide

Divides one value by another:

// Average score per subject (totalScore / numberOfSubjects)
db.students.aggregate([
  {
    $project: {
      name: 1,
      averageSubjectScore: {
        $divide: ["$totalScore", { $size: "$subjects" }]
      }
    }
  }
])

$round

Rounds a number to a specified number of decimal places:

db.students.aggregate([
  {
    $group: {
      _id: "$grade",
      averageScore: { $avg: "$examScore" }
    }
  },
  {
    $project: {
      grade: "$_id",
      averageScore: { $round: ["$averageScore", 1] }
    }
  }
])

{ $round: ["$averageScore", 1] } rounds to 1 decimal place. Pass 0 to round to whole numbers.

$mod

Returns the remainder after division:

// Find students with an even roll number
db.students.aggregate([
  {
    $project: {
      name: 1,
      rollNumber: 1,
      isEvenRoll: { $eq: [{ $mod: ["$rollNumber", 2] }, 0] }
    }
  }
])

String Expressions

$concat

Joins strings together:

// Create a full label — "Ali Hassan (10th Grade)"
db.students.aggregate([
  {
    $project: {
      _id: 0,
      label: {
        $concat: ["$name", " (", "$grade", " Grade)"]
      }
    }
  }
])

Result:

[
  { label: "Ali Hassan (10th Grade)" },
  { label: "Sara Ahmed (9th Grade)" }
]

$toUpper and $toLower

Converts string to uppercase or lowercase:

db.students.aggregate([
  {
    $project: {
      _id: 0,
      nameUpper: { $toUpper: "$name" },
      gradeLower: { $toLower: "$grade" }
    }
  }
])

Result:

[
  { nameUpper: "ALI HASSAN", gradeLower: "10th" },
  { nameUpper: "SARA AHMED", gradeLower: "9th" }
]

$substr

Extracts a substring — pass the string, starting position, and length:

// Get first 3 characters of the course code
db.courses.aggregate([
  {
    $project: {
      _id: 0,
      title: 1,
      codePrefix: { $substr: ["$code", 0, 3] }
    }
  }
])

Result:

[
  { title: "Mathematics", codePrefix: "MAT" },
  { title: "Physics",     codePrefix: "PHY" }
]

$strLenCP

Returns the length of a string:

db.students.aggregate([
  {
    $project: {
      name: 1,
      nameLength: { $strLenCP: "$name" }
    }
  }
])

Date Expressions

$dateToString

Formats a Date field as a readable string:

db.students.aggregate([
  {
    $project: {
      name: 1,
      enrollmentFormatted: {
        $dateToString: {
          format: "%d-%m-%Y",
          date: "$enrollmentDate"
        }
      }
    }
  }
])

Result:

[
  { name: "Ali Hassan", enrollmentFormatted: "01-09-2024" },
  { name: "Sara Ahmed", enrollmentFormatted: "01-09-2024" }
]

Common format tokens:

TokenMeaningExample
%Y4-digit year2024
%mMonth (01–12)09
%dDay (01–31)01
%HHour (00–23)14
%MMinute (00–59)30

$year, $month, $dayOfMonth

Extract specific parts of a date:

db.students.aggregate([
  {
    $project: {
      name: 1,
      enrollmentYear:  { $year:  "$enrollmentDate" },
      enrollmentMonth: { $month: "$enrollmentDate" },
      enrollmentDay:   { $dayOfMonth: "$enrollmentDate" }
    }
  }
])

Group by year

// Count students enrolled per year
db.students.aggregate([
  {
    $group: {
      _id: { $year: "$enrollmentDate" },
      count: { $sum: 1 }
    }
  },
  { $sort: { _id: 1 } },
  { $project: { _id: 0, year: "$_id", count: 1 } }
])

Result:

[
  { year: 2022, count: 38 },
  { year: 2023, count: 45 },
  { year: 2024, count: 41 }
]

Conditional Expressions

$cond

Works like an if-else. Takes a condition, a value if true, and a value if false:

// Label students as "Pass" or "Fail" based on exam score
db.students.aggregate([
  {
    $project: {
      name: 1,
      examScore: 1,
      result: {
        $cond: {
          if: { $gte: ["$examScore", 50] },
          then: "Pass",
          else: "Fail"
        }
      }
    }
  }
])

Result:

[
  { name: "Ali Hassan", examScore: 88, result: "Pass" },
  { name: "Sara Ahmed", examScore: 42, result: "Fail" }
]

$ifNull

Returns a fallback value if a field is null or missing:

// Show "Not Assigned" if a student has no guardian set
db.students.aggregate([
  {
    $project: {
      name: 1,
      guardianName: {
        $ifNull: ["$guardian.name", "Not Assigned"]
      }
    }
  }
])

School System Examples

// Full student summary with computed fields
db.students.aggregate([
  { $match: { enrolled: true } },
  {
    $project: {
      _id: 0,
      fullLabel: { $concat: ["$name", " — ", "$grade"] },
      age: 1,
      birthYear: { $subtract: [2024, "$age"] },
      examScore: 1,
      result: {
        $cond: {
          if: { $gte: ["$examScore", 50] },
          then: "Pass",
          else: "Fail"
        }
      },
      city: "$address.city",
      enrolledSince: {
        $dateToString: { format: "%d-%m-%Y", date: "$enrollmentDate" }
      }
    }
  }
])

// Grade summary with rounded averages
db.students.aggregate([
  { $match: { enrolled: true } },
  {
    $group: {
      _id: "$grade",
      totalStudents: { $sum: 1 },
      averageScore: { $avg: "$examScore" },
      highestScore: { $max: "$examScore" },
      lowestScore: { $min: "$examScore" },
      totalFees: { $sum: "$feesPaid" },
      cities: { $addToSet: "$address.city" },
      topStudent: { $first: "$name" }
    }
  },
  { $sort: { averageScore: -1 } },
  {
    $project: {
      _id: 0,
      grade: "$_id",
      totalStudents: 1,
      averageScore: { $round: ["$averageScore", 1] },
      highestScore: 1,
      lowestScore: 1,
      totalFees: 1,
      cities: 1,
      topStudent: 1
    }
  }
])

// Students enrolled per year
db.students.aggregate([
  {
    $group: {
      _id: { $year: "$enrollmentDate" },
      count: { $sum: 1 },
      students: { $push: "$name" }
    }
  },
  { $sort: { _id: 1 } },
  { $project: { _id: 0, year: "$_id", count: 1, students: 1 } }
])

// Pass/fail summary per grade
db.students.aggregate([
  { $match: { enrolled: true } },
  {
    $project: {
      grade: 1,
      result: {
        $cond: {
          if: { $gte: ["$examScore", 50] },
          then: "Pass",
          else: "Fail"
        }
      }
    }
  },
  {
    $group: {
      _id: { grade: "$grade", result: "$result" },
      count: { $sum: 1 }
    }
  },
  { $sort: { "_id.grade": 1 } }
])

Quick Reference

ExpressionTypeWhat it does
$sumAccumulatorSum values or count documents
$avgAccumulatorAverage of values
$min / $maxAccumulatorSmallest / largest value
$countAccumulatorCount documents
$pushAccumulatorCollect values into array
$addToSetAccumulatorCollect unique values into array
$first / $lastAccumulatorFirst / last value in group
$addArithmeticAdd numbers
$subtractArithmeticSubtract numbers
$multiplyArithmeticMultiply numbers
$divideArithmeticDivide numbers
$roundArithmeticRound to N decimal places
$concatStringJoin strings together
$toUpper / $toLowerStringChange string case
$substrStringExtract part of a string
$dateToStringDateFormat date as string
$year / $month / $dayOfMonthDateExtract date parts
$condConditionalIf-else logic
$ifNullConditionalFallback for null or missing fields

You do not need to memorize every expression. Learn the accumulators well — $sum, $avg, $push, $addToSet, $first — because you use them constantly inside $group. For arithmetic, string, and date expressions, know they exist and look up the exact syntax when you need them.

On this page