Definition
$replaceRootReplaces the input document with the specified document. The operation replaces all existing fields in the input document, including the
_idfield. You can promote an existing embedded document to the top level, or create a new document for promotion (see example).Note
You can also use the
$replaceWithstage. The$replaceWithstage peforms the same action as the$replaceRootstage, but the stages have different forms.The
$replaceRootstage has the following form:{ $replaceRoot: { newRoot: <replacementDocument> } } The replacement document can be any valid expression that resolves to a document. The stage errors and fails if
<replacementDocument>is not a document. For more information on expressions, see Expressions.
Behavior
If the <replacementDocument> is not a document,
$replaceRoot errors and fails.
If the <replacementDocument> resolves to a missing document (i.e.
the document does not exist), $replaceRoot errors and
fails. For example, create a collection with the following
documents:
db.collection.insertMany([ { "_id": 1, "name" : { "first" : "John", "last" : "Backus" } }, { "_id": 2, "name" : { "first" : "John", "last" : "McCarthy" } }, { "_id": 3, "name": { "first" : "Grace", "last" : "Hopper" } }, { "_id": 4, "firstname": "Ole-Johan", "lastname" : "Dahl" }, ])
Then the following $replaceRoot operation fails because one
of the documents does not have the name field:
db.collection.aggregate([ { $replaceRoot: { newRoot: "$name" } } ])
To avoid the error, you can use $mergeObjects to merge
the name document into some default document; for example:
db.collection.aggregate([ { $replaceRoot: { newRoot: { $mergeObjects: [ { _id: "$_id", first: "", last: "" }, "$name" ] } } } ])
Alternatively, you can skip the documents that are missing the name field by
including a $match stage to check for existence of the
document field before passing documents to the $replaceRoot
stage:
db.collection.aggregate([ { $match: { name : { $exists: true, $not: { $type: "array" }, $type: "object" } } }, { $replaceRoot: { newRoot: "$name" } } ])
Or, you can use $ifNull expression to specify some other
document to be root; for example:
db.collection.aggregate([ { $replaceRoot: { newRoot: { $ifNull: [ "$name", { _id: "$_id", missingName: true} ] } } } ])
Examples
$replaceRoot with an Embedded Document Field
A collection named people contains the following documents:
{ "_id" : 1, "name" : "Arlene", "age" : 34, "pets" : { "dogs" : 2, "cats" : 1 } } { "_id" : 2, "name" : "Sam", "age" : 41, "pets" : { "cats" : 1, "fish" : 3 } } { "_id" : 3, "name" : "Maria", "age" : 25 }
The following operation uses the $replaceRoot stage to
replace each input document with the result of a
$mergeObjects operation. The $mergeObjects
expression merges the specified default document with the pets
document.
db.people.aggregate( [ { $replaceRoot: { newRoot: { $mergeObjects: [ { dogs: 0, cats: 0, birds: 0, fish: 0 }, "$pets" ] }} } ] )
The operation returns the following results:
{ "dogs" : 2, "cats" : 1, "birds" : 0, "fish" : 0 } { "dogs" : 0, "cats" : 1, "birds" : 0, "fish" : 3 } { "dogs" : 0, "cats" : 0, "birds" : 0, "fish" : 0 }
$replaceRoot with a Document Nested in an Array
A collection named students contains the following documents:
db.students.insertMany([ { "_id" : 1, "grades" : [ { "test": 1, "grade" : 80, "mean" : 75, "std" : 6 }, { "test": 2, "grade" : 85, "mean" : 90, "std" : 4 }, { "test": 3, "grade" : 95, "mean" : 85, "std" : 6 } ] }, { "_id" : 2, "grades" : [ { "test": 1, "grade" : 90, "mean" : 75, "std" : 6 }, { "test": 2, "grade" : 87, "mean" : 90, "std" : 3 }, { "test": 3, "grade" : 91, "mean" : 85, "std" : 4 } ] } ])
The following operation promotes the embedded document(s) with the
grade field greater than or equal to 90 to the top level:
db.students.aggregate( [ { $unwind: "$grades" }, { $match: { "grades.grade" : { $gte: 90 } } }, { $replaceRoot: { newRoot: "$grades" } } ] )
The operation returns the following results:
{ "test" : 3, "grade" : 95, "mean" : 85, "std" : 6 } { "test" : 1, "grade" : 90, "mean" : 75, "std" : 6 } { "test" : 3, "grade" : 91, "mean" : 85, "std" : 4 }
$replaceRoot with a newly created document
You can also create new documents as part of the
$replaceRoot stage and use them to replace all the other fields.
A collection named contacts contains the following documents:
{ "_id" : 1, "first_name" : "Gary", "last_name" : "Sheffield", "city" : "New York" } { "_id" : 2, "first_name" : "Nancy", "last_name" : "Walker", "city" : "Anaheim" } { "_id" : 3, "first_name" : "Peter", "last_name" : "Sumner", "city" : "Toledo" }
The following operation creates a new document out of the
first_name and last_name fields.
db.contacts.aggregate( [ { $replaceRoot: { newRoot: { full_name: { $concat : [ "$first_name", " ", "$last_name" ] } } } } ] )
The operation returns the following results:
{ "full_name" : "Gary Sheffield" } { "full_name" : "Nancy Walker" } { "full_name" : "Peter Sumner" }
$replaceRoot with a New Document Created from $$ROOT and a Default Document
Create a collection named contacts with the following documents:
db.contacts.insertMany( [ { "_id" : 1, name: "Fred", email: "fred@example.net" }, { "_id" : 2, name: "Frank N. Stine", cell: "012-345-9999" }, { "_id" : 3, name: "Gren Dell", home: "987-654-3210", email: "beo@example.net" } ] )
The following operation uses $replaceRoot with
$mergeObjects to output current documents with default
values for missing fields:
db.contacts.aggregate( [ { $replaceRoot: { newRoot: { $mergeObjects: [ { _id: "", name: "", email: "", cell: "", home: "" }, "$$ROOT" ] } } } ] )
The aggregation returns the following documents:
{ _id: 1, name: 'Fred', email: 'fred@example.net', cell: '', home: '' }, { _id: 2, name: 'Frank N. Stine', email: '', cell: '012-345-9999', home: '' }, { _id: 3, name: 'Gren Dell', email: 'beo@example.net', cell: '', home: '987-654-3210' }
The C# examples on this page use the sample_mflix database from
the Atlas sample datasets. To learn how to
create a free MongoDB Atlas cluster and load the sample datasets, see
Get Started in the MongoDB
.NET/C# Driver documentation.
The following Movie class models the documents in the
sample_mflix.movies collection:
[] public class Movie { [] public ObjectId Id { get; set; } [] public string Title { get; set; } = null!; [] public int? Year { get; set; } [] public int? Runtime { get; set; } [] public string? Rated { get; set; } [] public int Metacritic { get; set; } [] public string? Plot { get; set; } [] public string? Type { get; set; } [] public string[]? Cast { get; set; } [] public string[]? Directors { get; set; } [] public string[]? Writers { get; set; } [] public ImdbData? Imdb { get; set; } }
The following ImdbData class models the embedded
imdb document:
[] public class ImdbData { [] public int? ImdbId { get; set; } [] public double? Rating { get; set; } [] public int? Votes { get; set; } }
To use the MongoDB .NET/C# driver to add a $replaceRoot stage to an aggregation
pipeline, call the ReplaceRoot() method on a PipelineDefinition object.
The following example creates a pipeline stage that filters for Movie documents that have an imdb field,
sorts them by title, limits the result to five documents, and
replaces each document with its embedded
ImdbData document:
var pipeline = new EmptyPipelineDefinition<Movie>() .Match(Builders<Movie>.Filter.Exists(m => m.Imdb)) .Sort(Builders<Movie>.Sort.Ascending(m => m.Title)) .Limit(5) .ReplaceRoot(m => m.Imdb);
{ "rating" : "...", "votes" : 142 } { "rating" : "...", "votes" : 77 } { "rating" : "...", "votes" : 1608 } { "rating" : "...", "votes" : 2532 } { "rating" : "...", "votes" : 24645 }
The Node.js examples on this page use the sample_mflix database from the
Atlas sample datasets. To learn how to create a free
MongoDB Atlas cluster and load the sample datasets, see Get Started in the MongoDB Node.js driver documentation.
To use the MongoDB Node.js driver to add a $replaceRoot stage to an aggregation
pipeline, use the $replaceRoot operator in a pipeline object.
The following example creates a pipeline stage that replaces each input movie document with the document stored
in its imdb property. The
example then runs the aggregation pipeline:
const pipeline = [{ $replaceRoot: { newRoot: "$imdb" } }]; const cursor = collection.aggregate(pipeline); return cursor;
Learn More
To learn more about related pipeline stages, see the $replaceRoot guide.