MongoDB $let Operator

Beginner
⏱️ 8 min read
📚 Updated: Jul 2026
🎯 4 Examples
Variables

What You’ll Learn

The $let operator defines local variables inside an aggregation expression. Compute a value once in vars, then reuse it in in — cleaner than repeating the same sub-expression many times.

01

Local Variables

Name and store values.

02

Syntax

vars + in.

03

$$ Reference

Double dollar variables.

04

Reuse Values

Avoid repetition.

05

Use Cases

Totals, labels, logic.

06

Nesting

Scoped inner vars.

Definition and Usage

In MongoDB’s aggregation framework, the $let operator binds one or more variables to expressions, then evaluates a final in expression that can reference those variables. For example, you might compute price × quantity once as $$lineTotal, then use it for tax, discount, and final amount fields without duplicating the multiplication.

Think of $let as a small let block inside your pipeline — similar to declaring a variable in JavaScript before using it in a return expression.

💡
Beginner Tip

Inside in, reference variables with double dollar signs: "$$total". A single $ refers to document fields like "$price". This is the same $$ convention used by $filter and $map.

📝 Syntax

The $let operator takes a vars object and an in expression:

mongosh
{
  $let: {
    vars: {
      <varName1>: <expression1>,
      <varName2>: <expression2>
    },
    in: <expression using $$varName1, $$varName2>
  }
}

Common Patterns

mongosh
// Single variable
{ $let: {
    vars: { total: { $multiply: [ "$price", "$qty" ] } },
    in: "$$total"
}}

// Multiple variables
{ $let: {
    vars: {
      subtotal: { $multiply: [ "$price", "$qty" ] },
      tax: { $multiply: [ { $multiply: [ "$price", "$qty" ] }, 0.1 ] }
    },
    in: { $add: [ "$$subtotal", "$$tax" ] }
}}

Syntax Rules

  • vars — object mapping variable names to expressions (computed once per document).
  • in — the final expression whose result becomes the output value.
  • Reference variables with $$varName (double dollar) inside in.
  • Variables in vars can reference earlier variables in the same vars object.
  • Use inside $project, $addFields, $set, $cond, and nested expressions.
  • $let can be nested — inner $let scopes are separate from outer ones.

💡 $ vs $$ in Aggregation Expressions

$price → field path on the current document
$$total → local variable defined in $let (or $filter / $map)
Literal string"active" (no dollar prefix)

⚡ Quick Reference

QuestionAnswer
Operator typeAggregation expression operator (variables)
Syntax{ $let: { vars: {...}, in: ... } }
Variable reference$$varName (double dollar)
OutputResult of the in expression
Common stages$project, $addFields, $cond
Basic
{
  $let: {
    vars: {
      total: {
        $multiply: [
          "$price", "$qty"
        ]
      }
    },
    in: "$$total"
  }
}

Compute and return

Multiple vars
{
  $let: {
    vars: {
      a: "$x",
      b: "$y"
    },
    in: {
      $add: ["$$a", "$$b"]
    }
  }
}

Two variables

In $cond
{
  $let: {
    vars: {
      t: { $add: [
        "$a", "$b"
      ]}
    },
    in: {
      $gte: ["$$t", 100]
    }
  }
}

Reuse in condition

Nested
{
  $let: {
    vars: { x: "$a" },
    in: {
      $let: {
        vars: { y: "$b" },
        in: {
          $add: ["$$x","$$y"]
        }
      }
    }
  }
}

Inner scope

Examples Gallery

Walk through sample order line items, compute totals with $let, and build readable multi-step expressions without repetition.

📚 Compute Once, Use Many Times

Start with an orders collection and use $let to calculate a line total from price and quantity.

Sample Input Documents

Suppose you have an orders collection with line item fields:

mongosh
[
  { "_id": ObjectId("609c26812e9274a86871bc6a"), "item": "Notebook", "price": 12.50, "quantity": 3 },
  { "_id": ObjectId("609c26812e9274a86871bc6b"), "item": "Pen Pack", "price": 8.99, "quantity": 2 },
  { "_id": ObjectId("609c26812e9274a86871bc6c"), "item": "Stapler", "price": 15.00, "quantity": 1 }
]

Example 1 — Basic $let for Line Total

Compute price × quantity once and return it as lineTotal:

mongosh
db.orders.aggregate([
  {
    $project: {
      item: 1,
      price: 1,
      quantity: 1,
      lineTotal: {
        $let: {
          vars: {
            total: {
              $multiply: [ "$price", "$quantity" ]
            }
          },
          in: "$$total"
        }
      }
    }
  }
])

How It Works

  • vars.total evaluates $multiply once per document.
  • in: "$$total" returns that value as the lineTotal field.
  • The same pattern scales when you need the total in multiple places inside in.

📈 Practical Patterns

Use multiple variables, combine with tax logic, and drive conditional labels.

Example 2 — Subtotal, Tax, and Grand Total

Define subtotal once, then compute tax and final amount from it:

mongosh
db.orders.aggregate([
  {
    $project: {
      item: 1,
      pricing: {
        $let: {
          vars: {
            subtotal: {
              $multiply: [ "$price", "$quantity" ]
            }
          },
          in: {
            subtotal: "$$subtotal",
            tax: {
              $multiply: [ "$$subtotal", 0.1 ]
            },
            grandTotal: {
              $multiply: [
                "$$subtotal",
                1.1
              ]
            }
          }
        }
      }
    }
  }
])

How It Works

$$subtotal is referenced three times inside in without repeating { $multiply: [ "$price", "$quantity" ] }. This keeps the pipeline readable and avoids calculation drift if the formula changes.

Example 3 — $let Inside $cond

Label orders as “bulk” or “standard” based on line total:

mongosh
db.orders.aggregate([
  {
    $project: {
      item: 1,
      orderType: {
        $let: {
          vars: {
            total: {
              $multiply: [ "$price", "$quantity" ]
            }
          },
          in: {
            $cond: [
              { $gte: [ "$$total", 30 ] },
              "bulk",
              "standard"
            ]
          }
        }
      }
    }
  }
])

How It Works

$let computes $$total first, then $cond uses it in the condition. You could add more fields in the same in block that also reference $$total.

Example 4 — Nested $let for Discount Tiers

Apply a discount rate based on quantity, then compute the final price:

mongosh
db.orders.aggregate([
  {
    $project: {
      item: 1,
      finalPrice: {
        $let: {
          vars: {
            base: {
              $multiply: [ "$price", "$quantity" ]
            }
          },
          in: {
            $let: {
              vars: {
                rate: {
                  $cond: [
                    { $gte: [ "$quantity", 3 ] },
                    0.9,
                    1.0
                  ]
                }
              },
              in: {
                $multiply: [ "$$base", "$$rate" ]
              }
            }
          }
        }
      }
    }
  }
])

How It Works

The outer $let defines $$base. The inner $let defines $$rate and can use $$base from the outer scope. Notebook (qty 3) gets a 10% discount: 37.5 × 0.9 = 33.75.

Bonus — Variables That Reference Other Variables

Later entries in vars can use earlier variables:

mongosh
db.orders.aggregate([
  {
    $project: {
      item: 1,
      summary: {
        $let: {
          vars: {
            subtotal: {
              $multiply: [ "$price", "$quantity" ]
            },
            tax: {
              $multiply: [
                "$$subtotal",
                0.1
              ]
            }
          },
          in: {
            subtotal: "$$subtotal",
            tax: "$$tax",
            total: {
              $add: [ "$$subtotal", "$$tax" ]
            }
          }
        }
      }
    }
  }
])

How It Works

The tax variable references $$subtotal defined earlier in the same vars object. MongoDB evaluates vars in order, so dependencies must be declared before use.

🚀 Use Cases

  • Avoid repetition — compute a complex expression once and reuse it in multiple fields.
  • Readable pipelines — name intermediate values like subtotal or margin instead of nested operator trees.
  • Conditional logic — pair with $cond or $switch using precomputed variables.
  • Multi-step calculations — chain tax, discount, and shipping fees in a clear order.

🧠 How $let Works

1

MongoDB evaluates vars

Each variable in vars is computed from field paths or expressions, in declaration order.

Bind
2

Variables become $$ references

Inside in, use $$varName to read the bound values for the current document.

Scope
3

The in expression runs

MongoDB evaluates in and returns its result as the output of the surrounding $let.

Output
=

Cleaner expressions

You get named intermediate values and less duplicated logic in your pipeline.

Conclusion

The $let operator is a small but powerful tool for writing readable aggregation expressions. It lets you name intermediate results, reuse them across fields, and nest scoped variables for multi-step calculations — without repeating the same sub-expression everywhere.

For beginners, remember the pattern: define values in vars, reference them with $$name in in, and keep variable names short but meaningful. When expressions grow complex, reach for $let before adding more nesting.

💡 Best Practices

✅ Do

  • Use meaningful variable names like subtotal or margin
  • Reference variables with $$varName inside in
  • Declare dependencies in order within vars
  • Extract repeated sub-expressions into $let
  • Keep in focused — return an object or value you need

❌ Don’t

  • Use single $ for local variables (use $$)
  • Reference a variable before it is defined in vars
  • Over-nest $let when one level with multiple vars suffices
  • Use $let as a pipeline stage (it is an expression operator)
  • Confuse $let with JavaScript let outside the pipeline

Key Takeaways

Knowledge Unlocked

Five things to remember about $let

Use these points when writing variable expressions in MongoDB.

5
Core concepts
🔢 02

$$ Reference

Double dollar vars.

Syntax
🛠 03

Reuse Values

Compute once.

Usage
🔄 04

$cond Ready

Precompute conditions.

Pattern
📑 05

Nestable

Inner scopes OK.

Advanced

❓ Frequently Asked Questions

$let defines local variables inside an aggregation expression and evaluates a final expression that can use those variables. It helps you compute a value once and reuse it, making pipelines easier to read.
The syntax is { $let: { vars: { <name>: <expression>, ... }, in: <expression> } }. Reference variables in the in expression with a double dollar prefix, like "$$total".
Use double dollar signs: if the variable is named total, reference it as "$$total" inside the in expression. A single $ refers to document fields; $$ refers to variables defined in $let or operators like $filter.
Yes. You can place a $let inside another $let's in expression to create scoped variables. Inner variables can shadow outer ones with the same name.
Use $let inside expression stages such as $project, $addFields, $set, and inside other expressions like $cond, $switch, and $map.

Continue the Operator Series

Move on to $literal for fixed literal values, or review $cond for conditional branching.

Next: $literal →

About the author

Mari Selvan M P
Mari Selvan M P 🔗

Developer, cloud engineer, and technical writer

  • Experience 12 years building web and cloud systems
  • Focus Full Stack Development, AWS, and Developer Education

I write practical tutorials so students and working developers can learn by doing—from databases and APIs to deployment on AWS.

5 people found this page helpful