Definición
$replaceWithReemplaza el documento de entrada por el documento especificado. Esta operación reemplaza todos los campos existentes en el documento de entrada, incluido el
_idcampo. Con, puede promover un documento incrustado al nivel superior. También puede especificar un nuevo documento como$replaceWithreemplazo.La etapa realiza la misma acción que
$replaceWithla$replaceRootetapa, pero las etapas tienen diferentes formas.La etapa
$replaceWithtiene el siguiente formato:{ $replaceWith: <replacementDocument> } El documento de reemplazo puede ser cualquier expresión válida que se resuelva en un documento. Para obtener más información sobre las expresiones, consulta Expresiones.
Comportamiento
Si el <replacementDocument> no es un documento, $replaceWith produce errores y falla.
Si el <replacementDocument> se resuelve en un documento inexistente (es decir, el documento no existe), $replaceWith genera un error y falla. Por ejemplo, crea 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 falla porque uno de los documentos no tiene $replaceWith el name campo:
db.collection.aggregate([ { $replaceWith: "$name" } ])
Para evitar el error, puede utilizar para fusionar $mergeObjects el name documento con algún documento predeterminado; por ejemplo:
db.collection.aggregate([ { $replaceWith: { $mergeObjects: [ { _id: "$_id", first: "", last: "" }, "$name" ] } } ])
Alternativamente, puede omitir los documentos que no tienen el campo name incluyendo una etapa $match para verificar la existencia del campo del documento antes de pasar los documentos a la etapa $replaceWith:
db.collection.aggregate([ { $match: { name : { $exists: true, $not: { $type: "array" }, $type: "object" } } }, { $replaceWith: "$name" } ])
O bien, puede usar la expresión $ifNull para especificar algún otro documento como raíz; por ejemplo:
db.collection.aggregate([ { $replaceWith: { $ifNull: [ "$name", { _id: "$_id", missingName: true} ] } } ])
Ejemplos
$replaceWith un campo de documento incrustado
Cree una colección llamada people con 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 $replaceWith para reemplazar cada documento de entrada con el resultado de una operación $mergeObjects. La expresión $mergeObjects fusiona el documento por defecto especificado con el documento pets.
db.people.aggregate( [ { $replaceWith: { $mergeObjects: [ { dogs: 0, cats: 0, birds: 0, fish: 0 }, "$pets" ] } } ] )
La operación devuelve los siguientes resultados:
{ "dogs" : 2, "cats" : 1, "birds" : 0, "fish" : 0 } { "dogs" : 0, "cats" : 1, "birds" : 0, "fish" : 3 } { "dogs" : 0, "cats" : 0, "birds" : 0, "fish" : 0 }
$replaceWith un documento anidado en una matriz
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 } } }, { $replaceWith: "$grades" } ] )
La operación devuelve los siguientes resultados:
{ "test" : 3, "grade" : 95, "mean" : 85, "std" : 6 } { "test" : 1, "grade" : 90, "mean" : 75, "std" : 6 } { "test" : 3, "grade" : 91, "mean" : 85, "std" : 4 }
$replaceWith un documento recién creado
Ejemplo 1
Una colección de ejemplo sales se rellena con los siguientes documentos:
db.sales.insertMany([ { "_id" : 1, "item" : "butter", "price" : 10, "quantity": 2, date: ISODate("2019-03-01T08:00:00Z"), status: "C" }, { "_id" : 2, "item" : "cream", "price" : 20, "quantity": 1, date: ISODate("2019-03-01T09:00:00Z"), status: "A" }, { "_id" : 3, "item" : "jam", "price" : 5, "quantity": 10, date: ISODate("2019-03-15T09:00:00Z"), status: "C" }, { "_id" : 4, "item" : "muffins", "price" : 5, "quantity": 10, date: ISODate("2019-03-15T09:00:00Z"), status: "C" } ])
Supongamos que, para fines de informes, desea calcular el importe total de cada venta completada al momento de la ejecución del informe. La siguiente operación busca todas las ventas con estado C y crea nuevos documentos utilizando la etapa$replaceWith. La etapa$replaceWithcalcula el importe total y utiliza la variableNOWpara obtener la hora actual.
db.sales.aggregate([ { $match: { status: "C" } }, { $replaceWith: { _id: "$_id", item: "$item", amount: { $multiply: [ "$price", "$quantity"]}, status: "Complete", asofDate: "$$NOW" } } ])
La operación devuelve los siguientes documentos:
{ "_id" : 1, "item" : "butter", "amount" : 20, "status" : "Complete", "asofDate" : ISODate("2019-06-03T22:47:54.812Z") } { "_id" : 3, "item" : "jam", "amount" : 50, "status" : "Complete", "asofDate" : ISODate("2019-06-03T22:47:54.812Z") } { "_id" : 4, "item" : "muffins", "amount" : 50, "status" : "Complete", "asofDate" : ISODate("2019-06-03T22:47:54.812Z") }
Ejemplo 2
Se completa una colección de ejemplo reportedsales con la información de ventas reportada por trimestre y regiones:
db.reportedsales.insertMany( [ { _id: 1, quarter: "2019Q1", region: "A", qty: 400 }, { _id: 2, quarter: "2019Q1", region: "B", qty: 550 }, { _id: 3, quarter: "2019Q1", region: "C", qty: 1000 }, { _id: 4, quarter: "2019Q2", region: "A", qty: 660 }, { _id: 5, quarter: "2019Q2", region: "B", qty: 500 }, { _id: 6, quarter: "2019Q2", region: "C", qty: 1200 } ] )
Supongamos que para fines de informes, desea ver los datos de ventas informados por trimestre; por ejemplo:
{ "_id" : "2019Q1", "A" : 400, "B" : 550, "C" : 1000 }
Para ver los datos agrupados por trimestre, puede utilizar la siguiente secuencia de agregación:
db.reportedsales.aggregate( [ { $addFields: { obj: { k: "$region", v: "$qty" } } }, { $group: { _id: "$quarter", items: { $push: "$obj" } } }, { $project: { items2: { $concatArrays: [ [ { "k": "_id", "v": "$_id" } ], "$items" ] } } }, { $replaceWith: { $arrayToObject: "$items2" } } ] )
- Primera etapa:
La etapa añade un
$addFieldsnuevoobjcampo de documento que define la clavekcomo el valor de la región y el valorvcomo la cantidad de dicha región. Por ejemplo:{ "_id" : 1, "quarter" : "2019Q1", "region" : "A", "qty" : 400, "obj" : { "k" : "A", "v" : 400 } } - Segunda fase:
La etapa
$groupagrupa por trimestre y utiliza$pushpara acumular los camposobjen un nuevo campo de matrizitems. Por ejemplo:{ "_id" : "2019Q1", "items" : [ { "k" : "A", "v" : 400 }, { "k" : "B", "v" : 550 }, { "k" : "C", "v" : 1000 } ] } - Tercera etapa:
La etapa
$projectutiliza$concatArrayspara crear un nuevo arregloitems2que incluye la información_idy los elementos del arregloitems:{ "_id" : "2019Q1", "items2" : [ { "k" : "_id", "v" : "2019Q1" }, { "k" : "A", "v" : 400 }, { "k" : "B", "v" : 550 }, { "k" : "C", "v" : 1000 } ] } - Cuarta etapa:
El
$replaceWithusa el para convertir$arrayToObjectelitems2en un documento, utilizando loskpares de clave y valor especificados,vy envía ese documento a la siguiente etapa. Por ejemplo:{ "_id" : "2019Q1", "A" : 400, "B" : 550, "C" : 1000 }
La agregación devuelve el siguiente documento:
{ "_id" : "2019Q1", "A" : 400, "B" : 550, "C" : 1000 } { "_id" : "2019Q2", "A" : 660, "B" : 500, "C" : 1200 }
$replaceWith un Nuevo Documento Creado desde $$ROOT y un Documento Predeterminado
Cree una colección llamada contacts con 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", cell: "987-654-3210", email: "beo@example.net" } ] )
La siguiente operación utiliza $replaceWith junto con $mergeObjects para generar los documentos actuales con valores por defecto para los campos faltantes:
db.contacts.aggregate( [ { $replaceWith: { $mergeObjects: [ { _id: "", name: "", email: "", cell: "", home: "" }, "$$ROOT" ] } } ] )
La agregación devuelve los siguientes documentos:
{ _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 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; } [] public DateTime LastUpdated { get; set; } }
Nota
ConventionPack para Pascal Case
Las clases de C# en esta página utilizan Pascal case para los nombres de sus propiedades, pero los nombres de los campos en la colección de MongoDB utilizan camel case. Para tener en cuenta esta diferencia, se puede usar el siguiente código para registrar un ConventionPack cuando la aplicación se inicie:
var camelCaseConvention = new ConventionPack { new CamelCaseElementNameConvention() }; ConventionRegistry.Register("CamelCase", camelCaseConvention, type => true);
La siguiente clase modela documentos ImdbData:
public class ImdbData { public string Id { get; set; } public int Votes { get; set; } public float Rating { get; set; } }
Para usar el controlador MongoDB.NET/C# para agregar una $replaceWith etapa a una canalización de agregación, llame a ReplaceWith()método en un PipelineDefinition objeto.
El siguiente ejemplo crea una etapa del pipeline que reemplaza cada documento Movie de entrada con el documento ImdbData almacenado en su propiedad Imdb:
var pipeline = new EmptyPipelineDefinition<Movie>() .ReplaceWith(m => m.ImdbData);
Los ejemplos de Node.js 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, consulte Primeros pasos en la documentación del controlador de MongoDB Node.js.
Para utilizar el controlador de MongoDB Node.js para agregar una etapa de $replaceWith a una canalización de agregación, utilice el Operador $replaceWith en un objeto de canalización.
El siguiente ejemplo crea una etapa de canalización que reemplaza cada documento de entrada movie con el documento almacenado en su campo imdb. A continuación, el ejemplo ejecuta la canalización de agregación:
const pipeline = [{ $replaceWith: { replacement: "$imdb" } }]; const cursor = collection.aggregate(pipeline); return cursor;
Obtén más información
Para aprender más sobre las etapas relacionadas del pipeline, consulta la guía $replaceRoot.