Filter concepts by levelShowing all levels.

MongoDB · Aggregation Expressions

Aggregation Expressions

The formula language inside a pipeline stage: arithmetic, branching, array operators, dates, and type conversion

  • Formulas, not filters$project/$set expressions compute values, $match filters documents
  • $switch over nested $condonce there are three or more branches
  • $map/$filter/$reducetransform an array in place, no $unwind needed
  • onError/onNullstop one bad document from aborting the whole pipeline

1.Aggregation expression categories

Aggregation expressions are the functions you use inside $project, $set, $group and other stages to compute a value from a document's fields, instead of just copying them through. They are grouped by what they work on: numbers, comparisons, strings, dates, arrays, and so on.

Key features

  • Every expression operator starts with $ and can be nested inside another expression
  • Arithmetic: $add, $subtract, $multiply, $divide, $mod
  • Comparison: $eq, $gt, $lt, and friends — same names as query operators, different context
  • Boolean: $and, $or, $not
  • String: $concat, $toUpper, $toLower, $substrCP, $trim
  • Array, conditional, object and conversion each have their own dedicated concept later in this section

Expression families and where each is used

Expression families and where each is used
FamilyExamplesTypical use
Arithmetic$add, $multiply, $dividecompute a total, a rate, a percentage
Comparison$eq, $gt, $ltebranch inside $cond or filter inside $filter
Boolean$and, $or, $notcombine multiple conditions into one
String$concat, $toUpper, $substrCPbuild a display label or normalize casing
Object$mergeObjects, $objectToArrayreshape a subdocument

Command

text
{ $operator: <expression> } or { $operator: [<expression>, ...] }

Expression operators ($add, $concat, $gt, …) are the pipeline's formula language — they compute a value inside a stage, and nest inside each other like function calls.

2.$cond, $ifNull, $switch

$cond is an if/then/else for one condition. $ifNull returns the first non-null value from a list, usually a default when a field is missing. $switch picks one of several branches by testing conditions in order, like an if/else-if chain.

Key features

  • $cond takes { if, then, else } or a 3-element array form [if, then, else]
  • $ifNull($field, default) returns default only when $field is missing, null, or undefined — not for 0, false, or ""
  • $switch evaluates branches in order and stops at the first true condition
  • $switch requires a default unless every possible case is covered by a branch — omitting it throws if no branch matches
  • All three can nest inside $set, $project, $group accumulators, or each other

Choosing between the three

Choosing between the three
OperatorShapeUse when
$ifNull$ifNull: [expr, fallback]one field, one fallback value
$cond$cond: { if, then, else }exactly two outcomes
$switch$switch: { branches, default }three or more mutually exclusive outcomes

Command

text
$ifNull: [<expr>, <fallback>] · $cond: { if, then, else } · $switch: { branches: [{ case, then }], default }

$ifNull is a fallback for one value, $cond is a two-way branch, $switch is an ordered if/else-if chain with a default — pick the smallest one that fits.

3.$map, $filter, $reduce

$map transforms every element of an array into something else. $filter keeps only the elements matching a condition. $reduce folds an array down into a single value, carrying an accumulator from element to element. All three run entirely inside the pipeline, without $unwind.

Key features

  • $map: { input: <array expr>, as: "<name>", in: <expr using $$name> } — same length as input, transformed
  • $filter: { input, as, cond } — cond using $$name, returns a shorter (or equal) array
  • $reduce: { input, initialValue, in } — in uses $$value (accumulator) and $$this (current element)
  • as defaults to "this" for $map/$filter if omitted, so $$this works without declaring it
  • All three can nest — $reduce over the output of a $filter over the output of a $map — to express a multi-step array pipeline in one expression
$unwind + $group vs. $map/$filter/$reduce for the same result

Unwind, then re-group

  • $unwind explodes the array into N documents
  • $group re-collapses them back to one
  • more pipeline documents in flight, more stages

Array expression

  • $map/$filter/$reduce work on the array in place
  • the document count never changes
  • one $set stage, no explode/re-collapse round trip
  • Unwind, then re-group
    • $unwind explodes the array into N documents
    • $group re-collapses them back to one
    • more pipeline documents in flight, more stages
  • Array expression
    • $map/$filter/$reduce work on the array in place
    • the document count never changes
    • one $set stage, no explode/re-collapse round trip

Command

text
$map: { input, as, in } · $filter: { input, as?, cond, limit? } · $reduce: { input, initialValue, in }

$map transforms, $filter keeps, $reduce folds — all three run inside the document, on the array field, without $unwind exploding it into multiple pipeline documents first.

4.Date expressions for grouping

Date expressions pull a piece out of a BSON date — year, month, day, hour, week, day-of-week — so you can $group events by that piece instead of by the exact timestamp, which would put almost every document in its own group.

Key features

  • $year, $month, $dayOfMonth, $hour, $minute, $isoWeek, $dayOfWeek each pull one component out of a date
  • $dateToString formats a date into a string using a format spec, often used directly as a $group _id
  • $dateTrunc rounds a date down to a unit (day, hour, week) while staying a Date, not a string
  • All date expressions accept an optional timezone argument — without one, they use UTC
  • $dateFromParts / $dateFromString build a date from components or parse one from text

Command

text
$dateTrunc: { date, unit, binSize?, timezone? } · $dateToString: { date, format, timezone? }

Pull the component you want to group by ($year, $dateToString, $dateTrunc) before grouping — grouping on the raw timestamp puts almost every document in its own bucket, and always pass a timezone if UTC is not what the business means by "day".

5.Type conversion expressions

$convert changes a value from one BSON type to another — string to int, string to date, and so on — and lets you specify what to do if the conversion fails or the input is null, instead of the pipeline just throwing an error.

Key features

  • $convert: { input, to, onError?, onNull? } — the general form with explicit failure handling
  • $toInt, $toDouble, $toDecimal, $toDate, $toString, $toBool are shorthand for common conversions with default error behavior
  • Without onError, a failed conversion throws and aborts the whole aggregation
  • onError provides a fallback value instead of throwing; onNull provides a value when the input is null or missing
  • $isNumber, $type let you check a value's type before deciding whether to convert it at all

Shorthand conversions and what they do on failure

Shorthand conversions and what they do on failure
ShorthandEquivalent toOn unconvertible input
$toInt$convert: { to: "int" }throws, unless wrapped in onError
$toDate$convert: { to: "date" }throws on an unparseable string
$toString$convert: { to: "string" }rarely fails — most types stringify

Command

text
$convert: { input, to, onError?, onNull? }

$convert (or its $to* shorthands) changes a value's BSON type — always set onError/onNull explicitly when the input quality is not guaranteed, or one bad document aborts the whole aggregation.

6.Expression cost and CPU pressure

Index usage bounds how many documents a pipeline examines, but not how much work each stage does once it has them — a $project or $group full of nested expressions runs real CPU work per document, and that cost is invisible to an index.

Signature

index bounds document count, not per-document expression cost

An index limits document count, not per-document compute — deeply nested expressions, regex, and string operations across millions of documents can be CPU-bound even with a perfect index.

Remember

  • Expression operators nest like function calls — an expression can be another expression's argument.
  • $ifNull for one fallback, $cond for two branches, $switch for three or more.
  • $map/$filter/$reduce work on an array field in place — no document-count change, unlike $unwind.
  • Always set onError/onNull on $convert when input quality is not guaranteed.

Pro tip

  • Pull a date down to the bucket you want ($dateToString, $dateTrunc) before grouping by it.
  • A perfect index bounds document count, not the CPU cost of a heavy expression per document.

Next up

  • $unwind and Array Processing
  • $lookup and Join-Like Operations
  • Window Functions and Advanced Analytics

Sources

  • Aggregation pipeline operators — mongodb.com/docs/manual/reference/operator/aggregation/
  • $reduce — mongodb.com/docs/manual/reference/operator/aggregation/reduce/
  • Checked 2026-09-10

Spotted a mistake on this page? Tell us.