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 valuesAccumulator 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:
| Token | Meaning | Example |
|---|---|---|
%Y | 4-digit year | 2024 |
%m | Month (01–12) | 09 |
%d | Day (01–31) | 01 |
%H | Hour (00–23) | 14 |
%M | Minute (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
| Expression | Type | What it does |
|---|---|---|
$sum | Accumulator | Sum values or count documents |
$avg | Accumulator | Average of values |
$min / $max | Accumulator | Smallest / largest value |
$count | Accumulator | Count documents |
$push | Accumulator | Collect values into array |
$addToSet | Accumulator | Collect unique values into array |
$first / $last | Accumulator | First / last value in group |
$add | Arithmetic | Add numbers |
$subtract | Arithmetic | Subtract numbers |
$multiply | Arithmetic | Multiply numbers |
$divide | Arithmetic | Divide numbers |
$round | Arithmetic | Round to N decimal places |
$concat | String | Join strings together |
$toUpper / $toLower | String | Change string case |
$substr | String | Extract part of a string |
$dateToString | Date | Format date as string |
$year / $month / $dayOfMonth | Date | Extract date parts |
$cond | Conditional | If-else logic |
$ifNull | Conditional | Fallback 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.