MongoDB $addFields Stage

Beginner
⏱️ 9 min read
📚 Updated: Jul 2026
🎯 5 Examples
Aggregation

What You’ll Learn

The $addFields stage adds new computed fields to each document in a pipeline while keeping existing fields—ideal for line totals, formatted labels, flags, and derived metrics before sorting or grouping.

01

Add columns

Keep all existing fields.

02

Expressions

$multiply, $concat, $cond.

03

vs $project

Additive vs reshape.

04

$set alias

Same syntax since 4.2.

05

Nested fields

Dot notation merge.

06

Pipeline order

Often after $match.

Definition and Usage

$addFields is an aggregation stage that outputs documents equal to the input documents plus any fields you define. Each new field’s value comes from an aggregation expression evaluated against the current document.

💡
Beginner tip

Think of $addFields as adding spreadsheet columns without deleting the originals. If you need to drop fields or show only a subset, use $project instead.

Use $addFields when downstream stages need calculated values—totals for $sort, categories for $group, or display strings before $limit. Pair with operators like $add and $multiply inside expressions.

📝 Syntax

$addFields takes a document mapping field names to expressions:

mongosh
{
  $addFields: {
    <newField1>: <expression1>,
    <newField2>: <expression2>,
    ...
  }
}

Syntax Rules

  • Preserves fields — all existing top-level fields remain unless overwritten by the same name.
  • Expression values — use field paths ("$price"), literals, or operator expressions.
  • Overwrite — assigning to an existing field name replaces that field’s value.
  • Nested keys — dot notation ("meta.source") or nested objects add sub-fields.
  • Multiple fields — add many computed columns in one stage.
  • Alias$set accepts identical syntax (MongoDB 4.2+).
mongosh
db.orders.aggregate([
  {
    $addFields: {
      lineTotal: { $multiply: ["$price", "$quantity"] }
    }
  }
]);

⚡ Quick Reference

QuestionAnswer
Stage typePipeline transformation (not accumulator)
Syntax{ $addFields: { field: expression } }
Existing fieldsKept by default
vs $project$addFields adds; $project reshapes/excludes
Alias$set (MongoDB 4.2+)
Common pairing$match$addFields$sort
Line total
lineTotal: {
  $multiply: ["$price", "$qty"]
}

Numeric expression

Full name
fullName: {
  $concat: ["$first", " ", "$last"]
}

String expression

Conditional
isPremium: {
  $gte: ["$score", 80]
}

Boolean flag

Nested
"meta.processed": true

Dot notation key

🧰 Parameters

The $addFields object defines one or more output fields:

field name Key

Name of the new (or replaced) field. Can be a simple identifier or dot notation for nested paths.

lineTotal: …
"address.zip": …
expression Value

Aggregation expression computed per document. References current fields with $ prefix.

{ $add: ["$a", "$b"] }
{ $cond: [ …, …, … ] }
input documents Preserved

Unless a field name collides, every input field appears unchanged in the output document.

_id, name, price → kept
order in pipeline Important

Stages run sequentially—fields added here are visible to later stages but not to earlier ones.

$match → $addFields → $group

Examples Gallery

Sample order line items—compute totals, build labels, compare with $project, and add conditional flags.

📚 Getting Started

Sample products and the core $addFields pattern.

Example 1 — Sample orders collection

mongosh
db.orders.insertMany([
  { product: "Keyboard", price: 45,  quantity: 2, firstName: "Sam",  lastName: "Lee",  score: 92 },
  { product: "Mouse",    price: 25,  quantity: 1, firstName: "Alex", lastName: "Kim",  score: 71 },
  { product: "Monitor",  price: 180, quantity: 1, firstName: "Jordan", lastName: "Wu", score: 85 }
]);

How It Works

Three orders with price, quantity, names, and scores—enough to demo numeric, string, and conditional expressions.

Example 2 — Add lineTotal with $multiply

mongosh
db.orders.aggregate([
  {
    $addFields: {
      lineTotal: { $multiply: ["$price", "$quantity"] }
    }
  },
  { $project: { product: 1, price: 1, quantity: 1, lineTotal: 1 } }
]);

/* Keyboard → lineTotal: 90  (45 × 2)
   Mouse    → lineTotal: 25
   Monitor  → lineTotal: 180 */
*/

How It Works

Every input field remains on the document; lineTotal is appended. The trailing $project trims output for readability only.

📈 Practical Patterns

Strings, reshaping comparison, and conditional fields.

Example 3 — Build fullName with $concat

mongosh
db.orders.aggregate([
  {
    $addFields: {
      fullName: {
        $concat: ["$firstName", " ", "$lastName"]
      }
    }
  },
  { $project: { fullName: 1, product: 1, _id: 0 } }
]);

/* Sam Lee, Alex Kim, Jordan Wu */
*/

How It Works

String expressions work the same as numeric ones—$addFields evaluates them per document and adds the result as a new field.

Example 4 — $addFields vs $project

mongosh
// $addFields — keeps ALL original fields + lineTotal
db.orders.aggregate([
  { $addFields: { lineTotal: { $multiply: ["$price", "$quantity"] } } },
  { $limit: 1 }
]);
// Output includes firstName, lastName, score, etc.

// $project — ONLY listed fields (plus _id unless suppressed)
db.orders.aggregate([
  {
    $project: {
      product: 1,
      lineTotal: { $multiply: ["$price", "$quantity"] }
    }
  },
  { $limit: 1 }
]);
// Output: product, lineTotal, _id only

How It Works

Use $addFields when you need one or two computed columns and want to keep the rest. Use $project when shaping a slim API response.

Example 5 — Conditional isHighValue with $cond

mongosh
db.orders.aggregate([
  {
    $addFields: {
      lineTotal: { $multiply: ["$price", "$quantity"] },
      tier: {
        $cond: {
          if: { $gte: ["$score", 85] },
          then: "gold",
          else: "standard"
        }
      }
    }
  },
  { $sort: { lineTotal: -1 } }
]);

/* Monitor → lineTotal: 180, tier: "gold" (score 85)
   Keyboard → lineTotal: 90,  tier: "gold" (score 92)
   Mouse → lineTotal: 25, tier: "standard" */
*/

How It Works

You can add multiple fields in one $addFields stage—later fields can reference earlier ones only if you split into two stages (each stage sees prior output).

🧠 How $addFields Works

1

Documents enter stage

Each document from the previous pipeline stage is processed independently.

Input
2

Expressions evaluated

MongoDB computes every value in the $addFields object against the current document.

Eval
3

Fields merged

New fields are merged onto the document copy. Name collisions overwrite the old value.

Merge
=

Enriched documents out

Downstream stages receive documents with the added fields available.

📝 Notes

  • $addFields does not write to the collection—it transforms documents in the pipeline only.
  • To reference a field added in the same stage, use a second $addFields stage—expressions in one object cannot refer to sibling keys being defined simultaneously.
  • $set and $addFields are interchangeable on MongoDB 4.2+.
  • Dot-notation keys merge into nested objects; they do not replace the entire parent object unless intended.
  • Place before $group when grouped accumulators need the computed field (e.g. group by lineTotal bucket).
  • Previous topic: Installation. Next: $bucket.

Conclusion

$addFields is the go-to stage for enriching documents with computed columns without dropping existing data. Map field names to expressions, chain stages as needed, and follow with $sort or $group.

When you only need a slim result set, combine with $project. When replacing the whole document, consider $replaceWith. Next: $bucket for categorical grouping.

💡 Best Practices

✅ Do

  • Use $addFields when you need a few computed columns on full documents
  • Put $match first to reduce documents before expensive expressions
  • Split dependent calculations across consecutive $addFields stages
  • Name fields clearly: lineTotal, fullName, isActive
  • Use $project at the end to trim fields for API responses

❌ Don’t

  • Use $addFields when you only need three fields—$project may be clearer
  • Assume sibling fields in one $addFields object can reference each other
  • Overwrite _id unintentionally with the same field name
  • Confuse pipeline $addFields with update operator $set on a single document
  • Store heavy nested objects when a flat field suffices

Key Takeaways

Knowledge Unlocked

Five things to remember about $addFields

Use these points whenever you enrich documents mid-pipeline.

5
Core concepts
📦 02

Expressions

Any operator allowed.

Syntax
📄 03

vs $project

Add vs reshape.

Compare
🔄 04

$set alias

Same behavior.

Tip
🛠 05

Pipeline order

Match → add → sort.

Pattern

❓ Frequently Asked Questions

$addFields adds one or more new fields to every document passing through the stage. All existing fields are kept unless you assign to the same field name—then the new expression replaces that field's value.
Anywhere in an aggregation pipeline where you need computed columns: { $addFields: { lineTotal: { $multiply: ["$price", "$quantity"] } } }. Common after $match and before $sort or $group.
$project reshapes output—you must explicitly include fields you want to keep (or use inclusion/exclusion rules). $addFields is additive: existing fields stay by default, so it is faster to write when you only need a few new columns.
Yes. MongoDB 4.2+ treats $set as an alias for $addFields—they accept the same syntax and behave identically.
Yes. Use dot notation as the key ("address.city") or nest objects: { address: { city: "$cityName" } }. Dot notation merges into existing nested objects when present.
Absolutely. Values can be field paths, literals, or any expression—$add, $multiply, $concat, $cond, $dateToString, and more.
Did you know?

Before $addFields existed, developers simulated it with $project using fieldName: 1 for every existing field plus the new expression—a verbose pattern that was easy to get wrong. $addFields (MongoDB 3.4+) made additive transforms a first-class stage. See the official $addFields docs.

Continue the Stages Series

Enrich documents with $addFields, then learn $bucket for range grouping.

Next: $bucket →

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