Variable and Reference Expressions
Variables and references — system variables,
$exprfor expressions in$match, and$letfor local variables.
← Previous | Index | Next: 15 - Set Operators →
Reference expressions let you use variables, access system state, and bridge the gap between query syntax and expression syntax.
$$ Operator — System Variables
MongoDB defines several system variables accessible via the $$ prefix.
$$CURRENT
Refers to the current document being processed in a pipeline stage. When you write a field path like "$title", it is actually shorthand for "$$CURRENT.title".
// These two are equivalent:
"$title"
"$$CURRENT.title"Example: Using $$CURRENT explicitly
db.projects.aggregate([
{
$match: {
$expr: {
$eq: ["$$CURRENT.type", "MANAGEMENT_PROJECT"]
}
}
},
{
$sort: { "$$CURRENT.type": -1 }
},
{ $out: "projectReport" }
]);In practice, you’ll almost always use the shorter
"$fieldName"form. But knowing about$$CURRENThelps when reading complex pipelines or when you need to be explicit about scope.
$expr — Use Expressions Inside $match
By default, the $match stage only accepts standard query operators ($eq, $gt, etc. in query syntax). It does not accept aggregation expressions.
The $expr operator bridges this gap — it lets you use any aggregation expression inside $match.
{
$match: {
$expr: { <expression> }
}
}Why is this needed?
Standard $match queries compare a field to a literal value:
{ $match: { price: { $gt: 100 } } } // field vs literal — works fineBut what if you want to compare two fields or use a computed value? That requires expressions:
{ $match: { $expr: { $gt: ["$price", "$cost"] } } } // field vs fieldExample: Filter projects with funding below 5000
db.projects.aggregate([
{
$addFields: {
projectFunding: { $sum: "$fundings.amount" }
}
},
{
$match: {
$expr: {
$lt: ["$projectFunding", 5000]
}
}
},
{
$project: {
projectFunding: 1,
title: 1,
description: 1
}
},
{
$sort: { projectFunding: 1 }
},
{ $out: "projectReport" }
]);When you need $expr vs. when you don’t
Standard $match (no $expr needed):
{ $match: { type: "REQUEST_PROJECT" } }
{ $match: { price: { $gt: 100 } } }
$expr required:
{ $match: { $expr: { $gt: ["$price", "$cost"] } } } // field vs field
{ $match: { $expr: { $eq: ["$type", "$$expectedType"] } } } // using variables
$let — Define Local Variables
The $let operator creates scoped variables within an expression. This is useful for breaking complex calculations into readable steps.
{
$let: {
vars: {
<var1>: <expression>,
<var2>: <expression>,
...
},
in: <expression> // can use $$var1, $$var2 here
}
}Variables defined in vars are only accessible within the in expression.
Example: Calculate adjusted funding
db.projects.aggregate([
{
$addFields: {
projectFunding: {
$let: {
vars: {
amount: { $sum: "$fundings.amount" }
},
in: {
$multiply: ["$$amount", 1.2] // 20% markup
}
}
}
}
}
]);This is equivalent to computing the sum first and then multiplying, but $let makes it clearer by naming the intermediate value.
When to use $let
- When an expression is used multiple times — define it once as a variable
- When a calculation has multiple steps — name each step for readability
- When passing data into a
$lookupsubquery (vialetin the$lookupstage — see 06 - Relationship Stages)
Variable Scope Summary
| Syntax | Scope | Example |
|---|---|---|
$fieldName | Current document’s field | "$title" → value of title |
$$CURRENT | Current document (explicit) | "$$CURRENT.title" → same as "$title" |
$$varName | Variable from $let or $lookup.let | "$$amount" |
$$this | Current element in $map/$reduce | Used inside in: |
$$value | Accumulator in $reduce | Used inside in: |
Next: 15 - Set Operators