Definición
$replaceRootReemplaza el documento de entrada con el documento especificado. La operación reemplaza todos los campos existentes en el documento de entrada, incluido el campo
_id. Puede promover un documento incrustado existente al nivel superior o crear un nuevo documento para su promoción (ver ejemplo).Nota
También puedes usar la etapa
$replaceWith. La etapa$replaceWithrealiza la misma acción que la etapa$replaceRoot, pero las etapas tienen formas diferentes.La etapa
$replaceRoottiene la siguiente forma:{ $replaceRoot: { newRoot: <replacementDocument> } } El documento de reemplazo puede ser cualquier expresión válida que se resuelva en un documento. La etapa presenta errores y falla si
<replacementDocument>no es un documento. Para obtener más información sobre expresiones, consulta Expresiones.
Comportamiento
Si <replacementDocument> no es un documento, $replaceRoot genera un error y falla.
Si <replacementDocument> se resuelve en un documento inexistente (es decir, el documento no existe), $replaceRoot genera un error y falla. Por ejemplo, cree una colección con los siguientes documentos:
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" }, ])
Entonces, la siguiente operación $replaceRoot falla porque uno de los documentos no tiene el campo name:
db.collection.aggregate([ { $replaceRoot: { newRoot: "$name" } } ])
Para evitar el error, puedes usar $mergeObjects para fusionar el documento name en algún documento por defecto; por ejemplo:
db.collection.aggregate([ { $replaceRoot: { newRoot: { $mergeObjects: [ { _id: "$_id", first: "", last: "" }, "$name" ] } } } ])
[ { _id: 1, first: 'John', last: 'Backus' }, { _id: 2, first: 'John', last: 'McCarthy' }, { _id: 3, first: 'Grace', last: 'Hopper' }, { _id: 4, first: '', last: '' } ]
Como alternativa, puede omitir los documentos a los que les falta el campo name incluyendo una etapa $match para comprobar la existencia del campo del documento antes de pasar los documentos a la etapa $replaceRoot:
db.collection.aggregate([ { $match: { name : { $exists: true, $not: { $type: "array" }, $type: "object" } } }, { $replaceRoot: { newRoot: "$name" } } ])
[ { first: 'John', last: 'Backus' }, { first: 'John', last: 'McCarthy' }, { first: 'Grace', last: 'Hopper' } ]
O bien, puede usar la expresión $ifNull para especificar algún otro documento como raíz; por ejemplo:
db.collection.aggregate([ { $replaceRoot: { newRoot: { $ifNull: [ "$name", { _id: "$_id", missingName: true} ] } } } ])
[ { first: 'John', last: 'Backus' }, { first: 'John', last: 'McCarthy' }, { first: 'Grace', last: 'Hopper' }, { _id: 4, missingName: true } ]
Ejemplos
$replaceRoot con un campo en un documento incrustado
Una colección llamada people contiene los siguientes documentos:
db.people.insertMany([ { "_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 } ])
La siguiente operación utiliza la etapa $replaceRoot para reemplazar cada documento de entrada con el resultado de una operación $mergeObjects. La expresión $mergeObjects combina el documento predeterminado especificado con el documento pets.
db.people.aggregate( [ { $replaceRoot: { newRoot: { $mergeObjects: [ { dogs: 0, cats: 0, birds: 0, fish: 0 }, "$pets" ] } } } ] )
[ { 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 con un documento anidado en un arreglo
Una colección llamada students contiene los siguientes documentos:
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 } ] } ])
La siguiente operación promueve los documentos incrustados con el campo grade que son mayores o iguales a 90 al nivel superior:
db.students.aggregate( [ { $unwind: "$grades" }, { $match: { "grades.grade" : { $gte: 90 } } }, { $replaceRoot: { newRoot: "$grades" } } ] )
[ { 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 con un documento recién creado
También puedes crear nuevos documentos como parte de la fase $replaceRoot y usarlos para reemplazar todos los demás campos.
Una colección llamada contacts contiene los siguientes documentos:
db.contacts.insertMany([ { "_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" } ])
La siguiente operación crea un nuevo documento a partir de los campos first_name y last_name.
db.contacts.aggregate( [ { $replaceRoot: { newRoot: { full_name: { $concat : [ "$first_name", " ", "$last_name" ] } } } } ] )
[ { full_name: 'Gary Sheffield' }, { full_name: 'Nancy Walker' }, { full_name: 'Peter Sumner' } ]
$replaceRoot con un nuevo documento creado a partir de $$ROOT y un documento por defecto
Una colección llamada contacts contiene los siguientes documentos:
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" } ] )
La siguiente operación utiliza $replaceRoot con $mergeObjects para generar los documentos actuales con valores predeterminados para los campos faltantes:
db.contacts.aggregate( [ { $replaceRoot: { newRoot: { $mergeObjects: [ { _id: "", name: "", email: "", cell: "", home: "" }, "$$ROOT" ] } } } ] )
[ { _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' } ]
Los ejemplos de C# en esta página utilizan la base de datos sample_mflix de los conjuntos de datos de muestra de Atlas. Para aprender a crear un clúster gratuito de MongoDB Atlas y cargar los conjuntos de datos de muestra, consulta Primeros pasos en la documentación del controlador de MongoDB .NET/C#.
La siguiente clase Movie modela los documentos en la colección sample_mflix.movies:
[] 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; } }
La siguiente clase ImdbData modela el documento incrustado imdb:
[] public class ImdbData { [] public int? ImdbId { get; set; } [] public double? Rating { get; set; } [] public int? Votes { get; set; } }
Para usar el controlador MongoDB.NET/C# para agregar una etapa $replaceRoot a una canalización de agregación, llame al método UnionWith() en un objeto PipelineDefinition.
El siguiente ejemplo crea una etapa de pipeline que filtra documentos Movie que tienen un campo imdb, los ordena por título, limita el resultado a cinco documentos y reemplaza cada documento con su documento ImdbData incorporado:
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);
Los ejemplos de Node.js de esta página utilizan la base de datos sample_mflix de los conjuntos de datos de ejemplo de Atlas. Para aprender a crear un clúster gratuito de MongoDB Atlas y cargar los conjuntos de datos de ejemplo, consulte la sección «Primeros pasos» en la documentación del controlador de MongoDB para Node.js.
Para utilizar el controlador de MongoDB Node.js para agregar una etapa de $replaceRoot a una canalización de agregación, utilice el Operador $replaceRoot en un objeto de canalización.
El siguiente ejemplo crea una etapa de pipeline que reemplaza cada documento de entrada movie con el documento almacenado en su propiedad imdb. A continuación, el ejemplo ejecuta el pipeline de agregación:
const pipeline = [{ $replaceRoot: { newRoot: "$imdb" } }]; const cursor = collection.aggregate(pipeline); return cursor;
Obtén más información
Para obtener más información sobre las etapas relacionadas del proceso, consulte la guía $replaceRoot.