The $set stage adds or overwrites fields on each document passing through the pipeline—computed totals, formatted labels, flags, and nested updates—without dropping the rest of the document.
01
Add fields
New columns.
02
Overwrite
Replace values.
03
Expressions
$multiply etc.
04
$cond
If/else fields.
05
Nested
Dot notation.
06
= $addFields
Same stage.
Fundamentals
Definition and Usage
$set is an aggregation stage that assigns one or more field values on every input document. Existing fields remain unless you assign to the same name—then the new expression replaces the old value. Think of it as “set these properties on each document as it flows through the pipeline.”
💡
Beginner tip
$project = choose which fields to show (reshape output). $set = keep everything and add/update a few fields. Since MongoDB 4.2, $set and $addFields are the same stage with different names.
Use $set after $match or $lookup when you need derived columns—line totals, full names, status labels, or audit timestamps—before $sort, $group, or returning results to the client.
Foundation
📝 Syntax
$set accepts an object of field names mapped to values or aggregation expressions:
Orders and customers collections—computed line totals, concatenated names, conditional labels, nested shipping updates, and enriching grouped results after $group.
The most common $set pattern: add a derived numeric field from existing columns. Filter first with $match, compute with $set, then optionally $project for API response shape.
Example 3 — Build fullName and overwrite display label
mongosh
db.customers.aggregate([
{
$set: {
fullName: {
$concat: ["$first", " ", "$last"]
},
label: {
$concat: ["$last", ", ", "$first"]
}
}
},
{
$project: {
_id: 0,
customerId: 1,
fullName: 1,
label: 1,
spend: 1
}
}
])
// fullName → "Ana Rivera" (new field)
// label → "Rivera, Ana" (new field)
// first and last still on document until excluded
📤 Formatted names:
C-01 fullName: Ana Rivera label: Rivera, Ana
C-02 fullName: Ben Cho label: Cho, Ben
C-04 fullName: Dan Wu label: Wu, Dan
How It Works
$concat inside $set builds display strings without changing stored data in the collection—transformations happen at query time in the pipeline.
📈 Practical Patterns
Conditionals, nested paths, and post-group enrichment.
Widget revenue: 100 avgOrderValue: 100
Gizmo revenue: 150 avgOrderValue: 150
Part revenue: 54 avgOrderValue: 54
Each row includes report.generatedAt + report.source
How It Works
$set is not only for raw collection documents—use it after $group to flatten _id into readable fields, compute averages, and attach nested audit metadata with dot notation.
Compare
📋 $set vs related transformation stages
Stage
Behavior
Best for
$set
Add or overwrite fields; keep others
Computed columns, flags, nested updates
$addFields
Identical to $set
Same—alternate name
$project
Include/exclude/rename output fields
Trimming response shape, hiding _id
$unset
Remove fields from documents
Drop temp or sensitive fields
$replaceWith
Replace entire document
Full document reshape—not partial set
🧠 How $set Works
1
Document enters
Each document from the prior stage arrives with its current field set—possibly filtered or joined data.
Input
2
Expressions evaluated
MongoDB evaluates every value in the $set object—literals, field paths, or nested expressions like $multiply.
Evaluate
3
Fields merged
New keys are added; existing keys are overwritten. Unmentioned fields pass through unchanged.
Merge
=
✎️
Enriched document
The document exits with added or updated fields—ready for $sort, $group, or client output.
Important
📝 Notes
$set and $addFields are aliases—same syntax since MongoDB 4.2.
Assigning to an existing field overwrites its value for pipeline documents—not a permanent collection update unless you use $merge or $out.
Use dot notation keys to update nested paths without replacing entire sub-documents.
$set does not remove fields—use $unset or $project exclusion for that.
Multiple $set stages in one pipeline are fine; each merges its assignments in order.
$set enriches pipeline documents: add computed fields, overwrite values, set nested paths, and attach metadata—while keeping the rest of each document intact.
Reach for $project when reshaping output; use $set when you only need a few new or updated fields. Next: $skip to offset documents for pagination.
Use $set for derived columns instead of repeating math in $project
Place $set after filters ($match) so expressions run on fewer documents
Use dot notation for single nested updates
Combine $set + $unset to add temp fields then clean up
Flatten $group output with $set: { product: "$_id" }
❌ Don’t
Use $set when you only need a slim API response—use $project
Assume pipeline $set updates the collection permanently
Replace entire nested objects when dot notation suffices
Forget that overwriting a field removes the old value in pipeline output
Chain ten separate $set stages when one stage with multiple keys works
Summary
Key Takeaways
Knowledge Unlocked
Five things to remember about $set
Use these points whenever you enrich documents mid-pipeline.
5
Core concepts
✎️01
Add / overwrite
Field merge.
Basics
📈02
Expressions
Compute values.
Syntax
🔗03
= $addFields
Same stage.
Alias
📁04
Dot notation
Nested paths.
Nested
📊05
After $group
Enrich summaries.
Pattern
❓ Frequently Asked Questions
$set adds new fields to documents or overwrites existing field values using aggregation expressions. All other fields stay on the document unless you assign to the same name—making $set ideal when you want to enrich data without reshaping the whole document.
Yes. Since MongoDB 4.2, $set is an alias for $addFields—they accept identical syntax and behave the same way. Use whichever name reads clearer in your pipeline; many teams prefer $set when updating fields and $addFields when adding computed columns.
$project controls which fields appear in output—you include or exclude explicitly. $set is additive: every existing field remains unless you overwrite it. Use $set when adding a few computed fields; use $project when trimming or renaming the output shape.
Yes. If you set a field name that already exists, the new expression replaces the old value. Example: { $set: { status: "reviewed" } } overwrites status for every document passing through the stage.
Yes. Use keys like "address.city": "$cityName" to merge into nested objects, or assign whole nested objects: { profile: { displayName: "$name" } }. Dot notation updates one nested path without removing sibling nested fields.
$unset removes fields from documents. Pairs naturally with $set: add computed values with $set, then drop temporary or sensitive fields with $unset before returning results.
Did you know?
MongoDB introduced $set and $unset in version 4.2 as readable companions to $addFields—mirroring update operator names ($set / $unset) so pipeline field changes feel familiar if you already know updateOne syntax. See the official $set docs.