Docs Menu
Docs Home
/
Database Manual
/ / /

$replaceRoot (aggregation)

$replaceRoot

Replaces the input document with the specified document. The operation replaces all existing fields in the input document, including the _id field. 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 $replaceWith stage. The $replaceWith stage peforms the same action as the $replaceRoot stage, but the stages have different forms.

The $replaceRoot stage 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 Expression Operators.

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} ] } } }
])

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 }

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 }

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" }

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 int Runtime { get; set; }
public string Title { get; set; }
public string Rated { get; set; }
public List<string> Genres { get; set; }
public string Plot { get; set; }
public ImdbData Imdb { get; set; }
public int Year { get; set; }
public int Index { get; set; }
public string[] Comments { get; set; }
[BsonElement("lastupdated")]
public DateTime LastUpdated { get; set; }
}

Note

ConventionPack for Pascal Case

The properties in the preceding class are named in Pascal case, but the field names in the MongoDB collection use camel case. To account for this difference, you can use the following code to register a ConventionPack when your application starts:

var camelCaseConvention = new ConventionPack { new CamelCaseElementNameConvention() };
ConventionRegistry.Register("CamelCase", camelCaseConvention, type => true);

The following class models ImdbData documents:

public class ImdbData
{
public string Id { get; set; }
public int Votes { get; set; }
public float Rating { 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 replaces each input Movie document with the ImdbData document stored in its Imdb property:

var pipeline = new EmptyPipelineDefinition<Movie>()
.ReplaceRoot(m => m.ImdbData);

Back

$redact

On this page