MongoDB $replaceRoot Stage

Beginner
5 min read
Updated: Oct 2026
3 examples
Live preview

What Is $replaceRoot?

$replaceRoot is a MongoDB aggregation stage that replaces the whole input document with newRoot. Use it to promote an embedded document to the top level, or to emit a newly built document shape.

Remember
$replaceRoot = swap the whole document

{ $replaceRoot: { newRoot: <document expression> } }

newRoot must resolve to a document
(missing / non-document → error)

Common:
  newRoot: "$name"              // promote nested object
  newRoot: { full: ... }        // build a new object

vs $replaceWith → same job, shorter form
vs $project     → reshape fields vs replace entire root
UsePrefer
Promote nested object to top$replaceRoot / $replaceWith
Keep outer doc; pick fields$project
Add fields; keep the rest$addFields

How to Use $replaceRoot in MongoDB

Choose what becomes the new document, ensure it is always a document, then place the stage in the pipeline.

  1. Decide the new root—a field path like "$name", or a built object.
  2. Optional: $match so every document has that nested field.
  3. Add { $replaceRoot: { newRoot: <expression> } }.
  4. If you still need _id or defaults, merge with $mergeObjects or guard with $ifNull.
PieceRequired?Role
newRootYesExpression that resolves to a document
Field pathCommonPromote an embedded object (e.g. "$name")
Built objectOptionalCreate a fresh document shape

Pseudocode

Pseudocode
for each document:
    next = evaluate(newRoot)
    if next is missing or not a document:
        error
    emit next   // old fields (including _id) are gone

Cheat Sheet

Keep these facts handy while promoting documents.

TopicDetail
TypeAggregation stage
Syntax{ $replaceRoot: { newRoot: <expression> } }
Promote nested{ $replaceRoot: { newRoot: "$name" } }
Build new{ $replaceRoot: { newRoot: { full_name: { $concat: [...] } } } }
Alias{ $replaceWith: "$name" } (same idea)
Missing fieldErrors—use $match, $ifNull, or $mergeObjects
With arrays$unwind then newRoot: "$item"

Live Preview

Pick a newRoot style and see how one person document changes.

Simulates $replaceRoot on { _id: 1, name: { first: "Grace", last: "Hopper" }, city: "NY" }.

Result
$replaceRoot: { newRoot: "$name" }

output:
  { first: "Grace", last: "Hopper" }

Worked Walkthrough — Promote Nested Name

A person document wraps first / last inside name. Goal: make that nested object the whole document.

Calculation
Document in:
  { _id: 1, name: { first: "Grace", last: "Hopper" }, city: "NY" }

$replaceRoot:
  newRoot: "$name"

Document out:
  { first: "Grace", last: "Hopper" }

Note: _id and city are gone unless you merge them into newRoot

MongoDB Examples

Insert sample people, promote a nested name, then build a new root. Run these in mongosh in order.

Example 1 — Sample Data

Two people with a nested name object and a city field.

mongosh
db.people.insertMany([
  {
    _id: 1,
    name: { first: "Grace", last: "Hopper" },
    city: "NY"
  },
  {
    _id: 2,
    name: { first: "Alan", last: "Turing" },
    city: "London"
  }
]);

How the Data Is Stored in MongoDB

After the insert, MongoDB keeps two documents in people. Run find() to see them:

mongosh
db.people.find()

Read each document like this:

FieldExamplePlain English
name{ first, last }Nested name object
city"NY"City (dropped when promoting name)

How It Works

  1. Insert once. insertMany adds two people.
  2. Name is nested. first and last live under name.
  3. Ready to promote. The next examples use $replaceRoot.

Example 2 — Promote Nested Document

Goal: make name the entire output document (outer _id and city are discarded).

mongosh
db.people.aggregate([
  {
    $replaceRoot: {
      newRoot: "$name"
    }
  }
]);

How It Works

  1. Evaluate newRoot. "$name" resolves to the nested object.
  2. Swap the root. That object becomes the whole document.
  3. Outer fields are gone. Previous _id and city are not kept.
  4. Same idea as $replaceWith. $replaceWith: "$name" is the shorter alias form.

Example 3 — Build a New Root

Goal: create a fresh document with full_name from first and last, and keep the original _id.

mongosh
db.people.aggregate([
  {
    $replaceRoot: {
      newRoot: {
        _id: "$_id",
        full_name: {
          $concat: ["$name.first", " ", "$name.last"]
        }
      }
    }
  }
]);

How It Works

  1. Build an object. newRoot is a new document, not a field path.
  2. Keep _id. _id: "$_id" copies the original id into the new root.
  3. Concat names. $concat joins name.first, a space, and name.last.
  4. Everything else is dropped. Nested name and city do not appear unless you add them.

Edge Cases & Pitfalls

Check these before using $replaceRoot in production pipelines.

missing

Missing newRoot fails the stage

If the field path is absent, aggregation errors. Use $match, $ifNull, or $mergeObjects with defaults.

type

newRoot must be a document

A string, number, or array is not valid. Promote an object field, or build { ... }.

_id

Original _id is discarded

Unless you copy it into newRoot, the output has no outer _id (or uses one from the nested doc).

vs project

Need fields from the outer doc? Plan ahead

After promote, outer fields are gone. Merge them into newRoot first, or use $project if you only need a reshape.

Performance Notes

ApproachCostBest for
Promote one nested fieldPer documentFlatten embedded objects for APIs
$match then replaceFilter firstSkip docs that would error
$unwind + replaceMore docsOne root per array element

Prefer $match before $replaceRoot when some documents lack the nested field. Pairing with $unwind multiplies documents—use it only when you need that shape.

Key Takeaways

  • Role: replace the whole document with newRoot.
  • Must be a document: missing or non-document values error.
  • Alias: $replaceWith is the same operation in shorter form.
  • vs $project: swap the root vs reshape fields on the current doc.

One line: $replaceRoot answers “what document should leave this stage instead of the current one?”

Frequently Asked Questions

$replaceRoot replaces the entire input document with a new document from newRoot. newRoot must resolve to a document—often an embedded field like $name, or a newly built object.
They do the same job. $replaceRoot uses { newRoot: <expression> }. $replaceWith takes the expression directly: { $replaceWith: <expression> }. Pick the form that reads clearer.
The old document—including _id—is discarded. Keep _id only if you put it in newRoot, for example with $mergeObjects or by setting _id: "$_id".
The stage errors. Guard with $ifNull, merge defaults via $mergeObjects, or $match for field existence before $replaceRoot.
$project reshapes fields on the current document. $replaceRoot throws away the outer document and substitutes newRoot as the whole document. Use it to flatten a nested object to the top level.
When each array element should become its own root document. $unwind first, then $replaceRoot: { newRoot: "$arrayField" }.

Next: $replaceWith

Replace the document with an expression using the shorter alias form.

$replaceWith tutorial →

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.

10 people found this page helpful