Definição
$replaceWithReplaces the input document with the specified document. The operation replaces all existing fields in the input document, including the
_idfield. With$replaceWith, you can promote an embedded document to the top-level. You can also specify a new document as the replacement.The
$replaceWithstage performs the same action as the$replaceRootstage, but the stages have different forms.The
$replaceWithstage has the following form:{ $replaceWith: <replacementDocument> } O documento de substituição pode ser qualquer expressão válida que se resolva a um documento. Para mais informações sobre expressões, consulte Expressões.
Comportamento
If the <replacementDocument> is not a document, $replaceWith errors and fails.
If the <replacementDocument> resolves to a missing document (i.e. the document does not exist), $replaceWith 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 $replaceWith operation fails because one of the document does not have the name field:
db.collection.aggregate([ { $replaceWith: "$name" } ])
Para evitar o erro, você pode usar $mergeObjects para mesclar o documento name com algum documento padrão. Por exemplo:
db.collection.aggregate([ { $replaceWith: { $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 $replaceWith stage:
db.collection.aggregate([ { $match: { name : { $exists: true, $not: { $type: "array" }, $type: "object" } } }, { $replaceWith: "$name" } ])
Ou você pode usar a expressão $ifNull para especificar algum outro documento como root. Por exemplo:
db.collection.aggregate([ { $replaceWith: { $ifNull: [ "$name", { _id: "$_id", missingName: true} ] } } ])
Exemplos
$replaceWith um campo de documento incorporado
Crie uma coleção denominada people com os seguintes 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 } ])
The following operation uses the $replaceWith 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( [ { $replaceWith: { $mergeObjects: [ { dogs: 0, cats: 0, birds: 0, fish: 0 }, "$pets" ] } } ] )
A operação retorna os seguintes 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 um documento agrupado em uma array
Uma coleção chamada students contém os seguintes 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 } ] } ])
A operação a seguir promove o(s) documento(s) incorporado(s) com o campo grade maior ou igual a 90 ao nível superior:
db.students.aggregate( [ { $unwind: "$grades" }, { $match: { "grades.grade" : { $gte: 90 } } }, { $replaceWith: "$grades" } ] )
A operação retorna os seguintes 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 um documento recém-criado
Exemplo 1
Uma collection de exemplo sales é preenchida com os seguintes 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" } ])
Assume that for reporting purposes, you want to calculate for each completed sale, the total amount as of the current report run time. The following operation finds all the sales with status C and creates new documents using the $replaceWith stage. The $replaceWith calculates the total amount as well as uses the variable NOW to get the current time.
db.sales.aggregate([ { $match: { status: "C" } }, { $replaceWith: { _id: "$_id", item: "$item", amount: { $multiply: [ "$price", "$quantity"]}, status: "Complete", asofDate: "$$NOW" } } ])
A operação retorna os seguintes documentos:
[ { _id: 1, item: 'butter', amount: 20, status: 'Complete', asofDate: '...' }, { _id: 3, item: 'jam', amount: 50, status: 'Complete', asofDate: '...' }, { _id: 4, item: 'muffins', amount: 50, status: 'Complete', asofDate: '...' } ]
Exemplo 2
Uma collection de exemplo reportedsales é preenchida com as informações de vendas relatadas por trimestre e regiões:
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 } ] )
Suponha que, para fins de relatório, você queira visualizar os dados de vendas relatados por trimestre. Por exemplo
{ "_id" : "2019Q1", "A" : 400, "B" : 550, "C" : 1000 }
Para visualizar os dados agrupados por trimestre, você pode usar o seguinte aggregation pipeline:
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" } } ] )
- Primeiro estágio:
O estágio
$addFieldsadiciona um novo campo de documentoobjque define a chavekcomo o valor da região e o valorvcomo a quantidade dessa região. Por exemplo:{ "_id" : 1, "quarter" : "2019Q1", "region" : "A", "qty" : 400, "obj" : { "k" : "A", "v" : 400 } } - Segundo estágio:
O estágio
$groupagrupa por trimestre e usa$pushpara acumular os camposobjem um novo campo de arrayitems. Por exemplo:{ "_id" : "2019Q1", "items" : [ { "k" : "A", "v" : 400 }, { "k" : "B", "v" : 550 }, { "k" : "C", "v" : 1000 } ] } - Terceiro estágio:
O estágio
$projectusa$concatArrayspara criar uma nova arrayitems2que inclui as informações_ide os elementos da arrayitems:{ "_id" : "2019Q1", "items2" : [ { "k" : "_id", "v" : "2019Q1" }, { "k" : "A", "v" : 400 }, { "k" : "B", "v" : 550 }, { "k" : "C", "v" : 1000 } ] } - Quarto estágio:
The
$replaceWithuses the$arrayToObjectto convert theitems2into a document, using the specified keykand valuevpairs and outputs that document to the next stage. For example:{ "_id" : "2019Q1", "A" : 400, "B" : 550, "C" : 1000 }
A aggregation retorna o seguinte documento:
[ { _id: '2019Q1', A: 400, B: 550, C: 1000 }, { _id: '2019Q2', A: 660, B: 500, C: 1200 } ]
$replaceWith um novo documento criado a partir de $$ROOT e um documento-padrão
Crie uma coleção denominada contacts com os seguintes 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" } ] )
The following operation uses $replaceWith with $mergeObjects to output current documents with default values for missing fields:
db.contacts.aggregate( [ { $replaceWith: { $mergeObjects: [ { _id: "", name: "", email: "", cell: "", home: "" }, "$$ROOT" ] } } ] )
A aggregation retorna os seguintes 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: '987-654-3210', home: '' } ]
Os exemplos de C# nesta página utilizam o banco de dados sample_mflix a partir dos conjuntos de dados de amostra do Atlas. Para saber como criar um cluster MongoDB Atlas gratuito e carregar os conjuntos de dados de exemplo, consulte Introdução na documentação do driver MongoDB .NET/C#.
A seguinte classe Movie modela os documentos na collection 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; } }
A seguinte classe ImdbData modela os documentos incorporados no campo imdb de cada Movie:
[] 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 $replaceWith stage to an aggregation pipeline, call the UnionWith() method on a PipelineDefinition object.
O exemplo a seguir cria um estágio de pipeline que classifica os documentos Movie em ordem alfabética por título, limita os resultados a cinco documentos e substitui cada documento Movie pelo documento ImdbData armazenado em sua propriedade Imdb:
var pipeline = new EmptyPipelineDefinition<Movie>() .Sort(Builders<Movie>.Sort.Ascending(m => m.Title)) .Limit(5) .ReplaceWith(m => m.Imdb);
Os exemplos do Node.js nesta página utilizam o banco de dados do sample_mflix a partir dos conjuntos de dados de amostra do Atlas. Para saber como criar um cluster gratuito do MongoDB Atlas e carregar os conjuntos de dados de exemplo, consulte Introdução na documentação do driver do MongoDB Node.js
Para usar o driver Node.js do MongoDB para adicionar um estágio $replaceWith a um pipeline de agregação , use o operador $replaceWith em um objeto de pipeline.
O exemplo a seguir cria um estágio de pipeline que substitui cada documento de entrada movie pelo documento armazenado em seu campo imdb. Em seguida, o exemplo executa o agregação pipeline:
const pipeline = [{ $replaceWith: '$imdb' }]; const cursor = collection.aggregate(pipeline); return cursor;
Saiba mais
Para saber mais sobre os estágios de pipeline relacionados, consulte o guia$replaceRoot.