Definição
Observação
This page describes the $merge stage, which outputs the aggregation pipeline results to a collection. For the $mergeObjects operator, which merges documents into a single document, see $mergeObjects.
$mergeWrites the results of the aggregation pipeline to a specified collection. The
$mergeoperator must be the last stage in the pipeline.The
$mergestage:Pode enviar para uma coleção no mesmo banco de dados ou em um banco de dados diferente.
Can output to the same collection that is being aggregated. For more information, see Output to the Same Collection that is Being Aggregated.
Consider the following points when using
$mergeor$outstages in an aggregation pipeline:A partir do MongoDB 5.0, os pipelines com um estágio
$mergepoderão ser executados em nós secundários do conjunto de réplicas se todos os nós do cluster tiverem o featureCompatibilityVersion definido como5.0ou superior e a preferência de leitura permitir leituras secundárias.nas versões anteriores do MongoDB , os pipelines com estágios
$outou$mergesempre são executados no nó principal, e a preferência de leitura não é considerada.
Cria uma nova coleta se a coleta de saída ainda não existir.
Pode incorporar resultados (inserir novos documentos, mesclar documentos, substituir documentos, manter documentos existentes, falhar a operação, processar documentos com um pipeline de atualização personalizado) a uma coleção existente.
Pode gerar saída para uma coleção fragmentada. A coleta de entrada também pode ser fragmentada.
For a comparison with the
$outstage which also outputs the aggregation results to a collection, see$mergeand$outComparison.
Observação
Visualizações materializadas sob demanda
$merge pode incorporar os resultados do pipeline em uma coleção de saída existente em vez de executar uma substituição completa da coleção. Essa funcionalidade permite que os usuários criem exibições materializadas sob demanda, em que o conteúdo da coleção de saída é atualizado de forma incremental quando o pipeline é executado.
Para obter mais informações sobre esse caso de uso, consulte Exibições materializadas sob demanda , bem como os exemplos nesta página.
As visualizações materializadas são separadas das exibições somente para leitura. Para obter informações sobre como criar visualizações somente para leitura, consulte exibições somente para leitura.
Compatibilidade
Você pode utilizar o $merge para implantações hospedadas nos seguintes ambientes:
- MongoDB Atlas: The fully managed service for MongoDB deployments in the cloud
MongoDB Enterprise: a versão autogerenciada e baseada em assinatura do MongoDB
MongoDB Community: uma versão com código disponível, de uso gratuito e autogerenciada do MongoDB
Sintaxe
$merge tem a seguinte sintaxe:
{ $merge: { into: <collection> -or- { db: <db>, coll: <collection> }, on: <identifier field> -or- [ <identifier field1>, ...], // Optional let: <variables>, // Optional whenMatched: <replace|keepExisting|merge|fail|pipeline>, // Optional whenNotMatched: <insert|discard|fail> // Optional } }
Por exemplo:
{ $merge: { into: "myOutput", on: "_id", whenMatched: "replace", whenNotMatched: "insert" } }
If using all default options for $merge, including writing to a collection in the same database, you can use the simplified form:
{ $merge: <collection> } // Output collection is in the same database
The $merge takes a document with the following fields:
Campo | Descrição | |||
|---|---|---|---|---|
A coleção de saída. Especifique uma das seguintes opções:
If the output collection does not exist,
A coleção de saída pode ser uma coleção fragmentada. | ||||
Opcional. Campo ou campos que atuam como um identificador exclusivo para um documento. O identificador determina se um documento de resultados corresponde a um documento existente na coleção de resultados. Especifique uma das seguintes opções:
Para o campo ou campos especificados:
O valor padrão para ativado depende da coleção de saída:
| ||||
Optional. The behavior of Você pode especificar:
| ||||
Opcional. Especifica variáveis para uso no pipeline whenMatched. Especifique um documento com os nomes de variáveis e expressões de valor: If unspecified, defaults to To access the variables in the whenMatched pipeline: Especifique o prefixo do sinal de dólar duplo ($$) juntamente com o nome da variável no formulário For examples, see Use Variables to Customize the Merge. | ||||
Optional. The behavior of Você pode especificar uma das strings de ação predefinidas: |
Considerações
_id Geração de campo
If the _id field is not present in a document from the aggregation pipeline results, the $merge stage generates it automatically.
For example, in the following aggregation pipeline, $project excludes the _id field from the documents passed into $merge. When $merge writes these documents to the "newCollection", $merge generates a new _id field and value.
db.sales.aggregate( [ { $project: { _id: 0 } }, { $merge : { into : "newCollection" } } ] )
Criar uma nova coleção se a coleta de saída não for existente
The $merge operation creates a new collection if the specified output collection does not exist.
The output collection is created when
$mergewrites the first document into the collection and is immediately visible.If the aggregation fails, any writes completed by the
$mergebefore the error will not be rolled back.
Observação
For a replica set or a standalone, if the output database does not exist, $merge also creates the database.
Para um cluster fragmentado, o banco de dados de saída especificado já deve existir.
If the output collection does not exist, $merge requires the on identifier to be the _id field. To use a different on field value for a collection that does not exist, you can create the collection first by creating a unique index on the desired field(s) first. For example, if the output collection newDailySales201905 does not exist and you want to specify the salesDate field as the on identifier:
db.newDailySales201905.createIndex( { salesDate: 1 }, { unique: true } ) db.sales.aggregate( [ { $match: { date: { $gte: new Date("2019-05-01"), $lt: new Date("2019-06-01") } } }, { $group: { _id: { $dateToString: { format: "%Y-%m-%d", date: "$date" } }, totalqty: { $sum: "$quantity" } } }, { $project: { _id: 0, salesDate: { $toDate: "$_id" }, totalqty: 1 } }, { $merge : { into : "newDailySales201905", on: "salesDate" } } ] )
Saída para uma coleção compartilhada
The $merge stage can output to a sharded collection. When the output collection is sharded, $merge uses the _id field and all the shard key fields as the default on identifier. If you override the default, the on identifier must include all the shard key fields:
{ $merge: { into: "<shardedColl>" or { db:"<sharding enabled db>", coll: "<shardedColl>" }, on: [ "<shardkeyfield1>", "<shardkeyfield2>",... ], // Shard key fields and any additional fields let: <variables>, // Optional whenMatched: <replace|keepExisting|merge|fail|pipeline>, // Optional whenNotMatched: <insert|discard|fail> // Optional } }
Por exemplo, utilize o método sh.shardCollection() para criar uma nova coleção fragmentada newrestaurants com o campo postcode como a chave fragmentada.
sh.shardCollection( "exampledb.newrestaurants", // Namespace of the collection to shard { postcode: 1 }, // Shard key );
The newrestaurants collection will contain documents with information on new restaurant openings by month (date field) and postcode (shard key); specifically, the on identifier is ["date", "postcode"] (the ordering of the fields does not matter). Because $merge requires a unique index with keys that correspond to the on identifier fields, create the unique index (the ordering of the fields do not matter): [1]
use exampledb db.newrestaurants.createIndex( { postcode: 1, date: 1 }, { unique: true } )
With the sharded collection restaurants and the unique index created, you can use $merge to output the aggregation results to this collection, matching on [ "date", "postcode" ] as in this example:
use exampledb db.openings.aggregate([ { $group: { _id: { date: { $dateToString: { format: "%Y-%m", date: "$date" } }, postcode: "$postcode" }, restaurants: { $push: "$restaurantName" } } }, { $project: { _id: 0, postcode: "$_id.postcode", date: "$_id.date", restaurants: 1 } }, { $merge: { into: "newrestaurants", "on": [ "date", "postcode" ], whenMatched: "replace", whenNotMatched: "insert" } } ])
| [1] | O método No exemplo anterior, como o identificador |
Substituir documentos ($merge) versus Substituir coleção ($out)
$merge can replace an existing document in the output collection if the aggregation results contain a document or documents that match based on the on specification. As such, $merge can replace all documents in the existing collection if the aggregation results include matching documents for all existing documents in the collection and you specify "replace" for whenMatched.
No entanto, para substituir uma coleção existente, independentemente dos resultados da agregação, use $out em vez disso.
Documentos existentes, _id e valores da chave de fragmento
The $merge errors if the $merge results in a change to an existing document's _id value.
Dica
To avoid this error, if the on field does not include the _id field, remove the _id field in the aggregation results to avoid the error, such as with a preceding $unset stage, and so on.
Additionally, for a sharded collection, $merge also generates an error if it results in a change to the shard key value of an exising document.
Any writes completed by the $merge before the error will not be rolled back.
Restrições de índice único
If the unique index used by $merge for on field(s) is dropped mid-aggregation, there is no guarantee that the aggregation will be killed. If the aggregation continues, there is no guarantee that documents do not have duplicate on field values.
If the $merge attempts to write a document that violates any unique index on the output collection, the operation generates an error. For example:
Insert a non-matching document that violates a unique index other than the index on the on field(s).
Substituir um documento existente por um novo documento que viole um índice exclusivo que não seja o índice do(s) campo(s) ligado(s).
Mescle os documentos correspondentes que resultam em um documento que viola um índice exclusivo diferente do índice no(s) campo(s) ligado(s).
Validação de esquema
Se sua coleção usar validação de esquema e tiver validationAction definido como error, inserir um documento inválido ou atualizar um documento com valores inválidos com $merge gerará um MongoServerError e o documento não será gravado na coleção de destino. Se houver vários documentos inválidos, apenas o primeiro documento inválido encontrado gerará um erro. Todos os documentos válidos são gravados na coleção de destino e todos os documentos inválidos não são gravados.
whenMatched Comportamento de pipeline
$merge insere o documento diretamente na coleção de saída quando todas as seguintes condições forem verdadeiras:
The value of whenMatched is an aggregation pipeline.
The value of whenNotMatched is
insert.Não há correspondência para um documento na coleção de saída.
$merge e comparação $out
With the introduction of $merge, MongoDB provides two stages, $merge and $out, for writing the results of the aggregation pipeline to a collection:
|
|
|
|
|
|
|
|
|
|
Saída para a mesma coleção que está sendo agregada
Aviso
Quando $merge gera saídas para a mesma coleção que está sendo agregada, os documentos podem ser atualizados várias vezes ou a operação pode resultar em um loop infinito. Esse comportamento ocorre quando a atualização realizada pelo $merge altera a localização física dos documentos armazenados no disco. Quando a localização física de um documento muda, $merge pode considerá-lo um documento totalmente novo , resultando em atualizações adicionais. Para obter mais informações sobre esse comportamento, consulte Problema de Halloween.
$merge can output to the same collection that is being aggregated. You can also output to a collection which appears in other stages of the pipeline, such as $lookup.
Restrições
Restrições | Descrição |
|---|---|
An aggregation pipeline cannot use | |
An aggregation pipeline cannot use | |
ver definição | |
|
|
|
|
|
|
| The |
Exemplos
Visualização materializada sob demanda: criação inicial
If the output collection does not exist, the $merge creates the collection.
Por exemplo, uma coleção chamada salaries no banco de dados zoo é preenchida com o salário do funcionário e o histórico do departamento:
db.getSiblingDB("zoo").salaries.insertMany([ { "_id" : 1, employee: "Ant", dept: "A", salary: 100000, fiscal_year: 2017 }, { "_id" : 2, employee: "Bee", dept: "A", salary: 120000, fiscal_year: 2017 }, { "_id" : 3, employee: "Cat", dept: "Z", salary: 115000, fiscal_year: 2017 }, { "_id" : 4, employee: "Ant", dept: "A", salary: 115000, fiscal_year: 2018 }, { "_id" : 5, employee: "Bee", dept: "Z", salary: 145000, fiscal_year: 2018 }, { "_id" : 6, employee: "Cat", dept: "Z", salary: 135000, fiscal_year: 2018 }, { "_id" : 7, employee: "Gecko", dept: "A", salary: 100000, fiscal_year: 2018 }, { "_id" : 8, employee: "Ant", dept: "A", salary: 125000, fiscal_year: 2019 }, { "_id" : 9, employee: "Bee", dept: "Z", salary: 160000, fiscal_year: 2019 }, { "_id" : 10, employee: "Cat", dept: "Z", salary: 150000, fiscal_year: 2019 } ])
You can use the $group and $merge stages to initially create a collection named budgets (in the reporting database) from the data currently in the salaries collection:
Observação
For a replica set or a standalone deployment, if the output database does not exist, $merge also creates the database.
Para uma implantação de cluster fragmentado, o banco de dados de saída especificado já deve existir.
db.getSiblingDB("zoo").salaries.aggregate( [ { $group: { _id: { fiscal_year: "$fiscal_year", dept: "$dept" }, salaries: { $sum: "$salary" } } }, { $merge : { into: { db: "reporting", coll: "budgets" }, on: "_id", whenMatched: "replace", whenNotMatched: "insert" } } ] )
Etapa
$grouppara agrupar os salários porfiscal_yearedept.
Para visualizar os documentos na nova coleção budgets:
db.getSiblingDB("reporting").budgets.find().sort( { _id: 1 } )
A coleção budgets contém os seguintes documentos:
{ "_id" : { "fiscal_year" : 2017, "dept" : "A" }, "salaries" : 220000 } { "_id" : { "fiscal_year" : 2017, "dept" : "Z" }, "salaries" : 115000 } { "_id" : { "fiscal_year" : 2018, "dept" : "A" }, "salaries" : 215000 } { "_id" : { "fiscal_year" : 2018, "dept" : "Z" }, "salaries" : 280000 } { "_id" : { "fiscal_year" : 2019, "dept" : "A" }, "salaries" : 125000 } { "_id" : { "fiscal_year" : 2019, "dept" : "Z" }, "salaries" : 310000 }
Visualização materializada sob demanda: atualizar/substituir dados
O exemplo a seguir usa as coleções no exemplo anterior.
A coleção do exemplo salaries contém o salário do funcionário e o histórico do departamento:
db.salaries.insertMany( [ { _id : 1, employee: "Ant", dept: "A", salary: 100000, fiscal_year: 2017 }, { _id : 2, employee: "Bee", dept: "A", salary: 120000, fiscal_year: 2017 }, { _id : 3, employee: "Cat", dept: "Z", salary: 115000, fiscal_year: 2017 }, { _id : 4, employee: "Ant", dept: "A", salary: 115000, fiscal_year: 2018 }, { _id : 5, employee: "Bee", dept: "Z", salary: 145000, fiscal_year: 2018 }, { _id : 6, employee: "Cat", dept: "Z", salary: 135000, fiscal_year: 2018 }, { _id : 7, employee: "Gecko", dept: "A", salary: 100000, fiscal_year: 2018 }, { _id : 8, employee: "Ant", dept: "A", salary: 125000, fiscal_year: 2019 }, { _id : 9, employee: "Bee", dept: "Z", salary: 160000, fiscal_year: 2019 }, { _id : 10, employee: "Cat", dept: "Z", salary: 150000, fiscal_year: 2019 } ] )
A coleção do exemplo budgets contém os orçamentos anuais cumulativos:
db.budgets.insertMany( [ { _id : { "fiscal_year" : 2017, "dept" : "A" }, "salaries" : 220000 }, { _id : { "fiscal_year" : 2017, "dept" : "Z" }, "salaries" : 115000 }, { _id : { "fiscal_year" : 2018, "dept" : "A" }, "salaries" : 215000 }, { _id : { "fiscal_year" : 2018, "dept" : "Z" }, "salaries" : 280000 }, { _id : { "fiscal_year" : 2019, "dept" : "A" }, "salaries" : 125000 }, { _id : { "fiscal_year" : 2019, "dept" : "Z" }, "salaries" : 310000 } ] )
Durante o ano fiscal atual (2019 neste exemplo), novos funcionários são adicionados à coleção salaries e novas contagens de funcionários são pré-alocadas para o próximo ano:
db.getSiblingDB("zoo").salaries.insertMany( [ { _id : 11, employee: "Wren", dept: "Z", salary: 100000, fiscal_year: 2019 }, { _id : 12, employee: "Zebra", dept: "A", salary: 150000, fiscal_year: 2019 }, { _id : 13, employee: "headcount1", dept: "Z", salary: 120000, fiscal_year: 2020 }, { _id : 14, employee: "headcount2", dept: "Z", salary: 120000, fiscal_year: 2020 } ] )
Para atualizar a coleção budgets para refletir as novas informações de salário, o seguinte pipeline de agregação utiliza:
$matchetapa para encontrar todos os documentos comfiscal_yearmaior ou igual a2019.Etapa
$grouppara agrupar os salários porfiscal_yearedept.$mergeto write the result set to thebudgetscollection, replacing documents with the same_idvalue (in this example, a document with the fiscal year and dept). For documents that do not have matches in the collection,$mergeinserts the new documents.
db.getSiblingDB("zoo").salaries.aggregate( [ { $match : { fiscal_year: { $gte : 2019 } } }, { $group: { _id: { fiscal_year: "$fiscal_year", dept: "$dept" }, salaries: { $sum: "$salary" } } }, { $merge : { into: { db: "reporting", coll: "budgets" }, on: "_id", whenMatched: "replace", whenNotMatched: "insert" } } ] )
Após a execução da agregação, exiba os documentos na coleção budgets:
db.getSiblingDB("reporting").budgets.find().sort( { _id: 1 } )
A coleção budgets incorpora os novos dados de salário para o ano fiscal 2019 e adiciona novos documentos para o ano fiscal 2020:
{ _id : { "fiscal_year" : 2017, "dept" : "A" }, "salaries" : 220000 } { _id : { "fiscal_year" : 2017, "dept" : "Z" }, "salaries" : 115000 } { _id : { "fiscal_year" : 2018, "dept" : "A" }, "salaries" : 215000 } { _id : { "fiscal_year" : 2018, "dept" : "Z" }, "salaries" : 280000 } { _id : { "fiscal_year" : 2019, "dept" : "A" }, "salaries" : 275000 } { _id : { "fiscal_year" : 2019, "dept" : "Z" }, "salaries" : 410000 } { _id : { "fiscal_year" : 2020, "dept" : "Z" }, "salaries" : 240000 }
Insira apenas novos dados
To ensure that the $merge does not overwrite existing data in the collection, set whenMatched to keepExisting or fail.
A coleção do exemplo salaries no banco de dados zoo contém o salário do funcionário e o histórico do departamento:
db.salaries.insertMany( [ { _id : 1, employee: "Ant", dept: "A", salary: 100000, fiscal_year: 2017 }, { _id : 2, employee: "Bee", dept: "A", salary: 120000, fiscal_year: 2017 }, { _id : 3, employee: "Cat", dept: "Z", salary: 115000, fiscal_year: 2017 }, { _id : 4, employee: "Ant", dept: "A", salary: 115000, fiscal_year: 2018 }, { _id : 5, employee: "Bee", dept: "Z", salary: 145000, fiscal_year: 2018 }, { _id : 6, employee: "Cat", dept: "Z", salary: 135000, fiscal_year: 2018 }, { _id : 7, employee: "Gecko", dept: "A", salary: 100000, fiscal_year: 2018 }, { _id : 8, employee: "Ant", dept: "A", salary: 125000, fiscal_year: 2019 }, { _id : 9, employee: "Bee", dept: "Z", salary: 160000, fiscal_year: 2019 }, { _id : 10, employee: "Cat", dept: "Z", salary: 150000, fiscal_year: 2019 } ] )
Uma coleção orgArchive no banco de dados reporting contém registros históricos da organização departamental dos últimos anos fiscais. Os registros arquivados não devem ser modificados.
db.orgArchive.insertMany( [ { _id : ObjectId("5cd8c68261baa09e9f3622be"), "employees" : [ "Ant", "Gecko" ], "dept" : "A", "fiscal_year" : 2018 }, { _id : ObjectId("5cd8c68261baa09e9f3622bf"), "employees" : [ "Ant", "Bee" ], "dept" : "A", "fiscal_year" : 2017 }, { _id : ObjectId("5cd8c68261baa09e9f3622c0"), "employees" : [ "Bee", "Cat" ], "dept" : "Z", "fiscal_year" : 2018 }, { _id : ObjectId("5cd8c68261baa09e9f3622c1"), "employees" : [ "Cat" ], "dept" : "Z", "fiscal_year" : 2017 } ] )
A coleção orgArchive tem um índice composto único nos campos fiscal_year e dept. Especificamente, deve haver no máximo um registro para a mesma combinação de ano fiscal e departamento:
db.getSiblingDB("reporting").orgArchive.createIndex ( { fiscal_year: 1, dept: 1 }, { unique: true } )
No final do ano fiscal atual (2019 neste exemplo), a coleção salaries contém os seguintes documentos:
db.salaries.insertMany( [ { _id : 1, "employee" : "Ant", "dept" : "A", "salary" : 100000, "fiscal_year" : 2017 }, { _id : 2, "employee" : "Bee", "dept" : "A", "salary" : 120000, "fiscal_year" : 2017 }, { _id : 3, "employee" : "Cat", "dept" : "Z", "salary" : 115000, "fiscal_year" : 2017 }, { _id : 4, "employee" : "Ant", "dept" : "A", "salary" : 115000, "fiscal_year" : 2018 }, { _id : 5, "employee" : "Bee", "dept" : "Z", "salary" : 145000, "fiscal_year" : 2018 }, { _id : 6, "employee" : "Cat", "dept" : "Z", "salary" : 135000, "fiscal_year" : 2018 }, { _id : 7, "employee" : "Gecko", "dept" : "A", "salary" : 100000, "fiscal_year" : 2018 }, { _id : 8, "employee" : "Ant", "dept" : "A", "salary" : 125000, "fiscal_year" : 2019 }, { _id : 9, "employee" : "Bee", "dept" : "Z", "salary" : 160000, "fiscal_year" : 2019 }, { _id : 10, "employee" : "Cat", "dept" : "Z", "salary" : 150000, "fiscal_year" : 2019 }, { _id : 11, "employee" : "Wren", "dept" : "Z", "salary" : 100000, "fiscal_year" : 2019 }, { _id : 12, "employee" : "Zebra", "dept" : "A", "salary" : 150000, "fiscal_year" : 2019 }, { _id : 13, "employee" : "headcount1", "dept" : "Z", "salary" : 120000, "fiscal_year" : 2020 }, { _id : 14, "employee" : "headcount2", "dept" : "Z", "salary" : 120000, "fiscal_year" : 2020 } ] )
Para atualizar a coleção orgArchive para incluir o ano fiscal 2019 que acabou de terminar, o seguinte pipeline de agregação usa:
Estágio
$matchpara encontrar todos os documentos comfiscal_yearigual a2019.$groupestágio para agrupar os funcionários porfiscal_yearedept.
db.getSiblingDB("zoo").salaries.aggregate( [ { $match: { fiscal_year: 2019 }}, { $group: { _id: { fiscal_year: "$fiscal_year", dept: "$dept" }, employees: { $push: "$employee" } } }, { $project: { _id: 0, dept: "$_id.dept", fiscal_year: "$_id.fiscal_year", employees: 1 } }, { $merge : { into : { db: "reporting", coll: "orgArchive" }, on: [ "dept", "fiscal_year" ], whenMatched: "fail" } } ] )
Após a operação, a coleção orgArchive contém os seguintes documentos:
{ "_id" : ObjectId("5caccc6a66b22dd8a8cc419f"), "employees" : [ "Ahn", "Bess" ], "dept" : "A", "fiscal_year" : 2017 } { "_id" : ObjectId("5caccc6a66b22dd8a8cc419e"), "employees" : [ "Ahn", "Gee" ], "dept" : "A", "fiscal_year" : 2018 } { "_id" : ObjectId("5caccd0b66b22dd8a8cc438e"), "employees" : [ "Ahn", "Zeb" ], "dept" : "A", "fiscal_year" : 2019 } { "_id" : ObjectId("5caccc6a66b22dd8a8cc41a0"), "employees" : [ "Carl" ], "dept" : "Z", "fiscal_year" : 2017 } { "_id" : ObjectId("5caccc6a66b22dd8a8cc41a1"), "employees" : [ "Bess", "Carl" ], "dept" : "Z", "fiscal_year" : 2018 } { "_id" : ObjectId("5caccd0b66b22dd8a8cc438d"), "employees" : [ "Bess", "Carl", "Wen" ], "dept" : "Z", "fiscal_year" : 2019 }
If the orgArchive collection already contained a document for 2019 for department "A" and/or "B", the aggregation fails because of the duplicate key error. However, any document inserted before the error will not be rolled back.
Se você especificar KeepExisting para o documento correspondente, a agregação não afetará o documento correspondente e não apresentará erro com erro de chave duplicada. Da mesma forma, se você especificar substituir, a operação não falhará; no entanto, a operação substituirá o documento existente.
Mesclar resultados de múltiplas coleções
By default, if a document in the aggregation results matches a document in the collection, the $merge stage merges the documents.
Uma coleção de exemplo purchaseorders é preenchida com as informações da ordem de compra por trimestre e regiões:
db.purchaseorders.insertMany( [ { _id: 1, quarter: "2019Q1", region: "A", qty: 200, reportDate: new Date("2019-04-01") }, { _id: 2, quarter: "2019Q1", region: "B", qty: 300, reportDate: new Date("2019-04-01") }, { _id: 3, quarter: "2019Q1", region: "C", qty: 700, reportDate: new Date("2019-04-01") }, { _id: 4, quarter: "2019Q2", region: "B", qty: 300, reportDate: new Date("2019-07-01") }, { _id: 5, quarter: "2019Q2", region: "C", qty: 1000, reportDate: new Date("2019-07-01") }, { _id: 6, quarter: "2019Q2", region: "A", qty: 400, reportDate: new Date("2019-07-01") }, ] )
Outra coleção 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, reportDate: new Date("2019-04-02") }, { _id: 2, quarter: "2019Q1", region: "B", qty: 550, reportDate: new Date("2019-04-02") }, { _id: 3, quarter: "2019Q1", region: "C", qty: 1000, reportDate: new Date("2019-04-05") }, { _id: 4, quarter: "2019Q2", region: "B", qty: 500, reportDate: new Date("2019-07-02") }, ] )
Suponha que, para fins de relatório, você queira visualizar os dados por trimestre no seguinte formato:
{ "_id" : "2019Q1", "sales" : 1950, "purchased" : 1200 } { "_id" : "2019Q2", "sales" : 500, "purchased" : 1700 }
You can use the $merge to merge in results from the purchaseorders collection and the reportedsales collection to create a new collection quarterlyreport.
Para criar a coleção quarterlyreport, você pode utilizar o seguinte pipeline:
db.purchaseorders.aggregate( [ { $group: { _id: "$quarter", purchased: { $sum: "$qty" } } }, // group purchase orders by quarter { $merge : { into: "quarterlyreport", on: "_id", whenMatched: "merge", whenNotMatched: "insert" } } ])
- Primeiro estágio:
O estágio
$groupagrupa por trimestre e usa$sumpara adicionar os camposqtyem um novo campopurchased. Por exemplo:Para criar a coleção
quarterlyreport, você pode usar este pipeline:{ "_id" : "2019Q2", "purchased" : 1700 } { "_id" : "2019Q1", "purchased" : 1200 } - Segundo estágio:
- The
$mergestage writes the documents to thequarterlyreportcollection in the same database. If the stage finds an existing document in the collection that matches on the_idfield, the stage merges the matching documents. Otherwise, the stage inserts the document. For the initial creation, no documents should match.
Para visualizar os documentos na coleção, execute a seguinte operação:
db.quarterlyreport.find().sort( { _id: 1 } )
A collection contém os seguintes documentos:
{ "_id" : "2019Q1", "sales" : 1200, "purchased" : 1200 } { "_id" : "2019Q2", "sales" : 1700, "purchased" : 1700 }
Da mesma forma, execute o seguinte pipeline de agregação na coleção reportedsales para mesclar os resultados de vendas na coleção quarterlyreport.
db.reportedsales.aggregate( [ { $group: { _id: "$quarter", sales: { $sum: "$qty" } } }, // group sales by quarter { $merge : { into: "quarterlyreport", on: "_id", whenMatched: "merge", whenNotMatched: "insert" } } ])
- Primeiro estágio:
O estágio
$groupagrupa por trimestre e usa$sumpara adicionar os camposqtyem um novo camposales. Por exemplo:{ "_id" : "2019Q2", "sales" : 500 } { "_id" : "2019Q1", "sales" : 1950 } - Segundo estágio:
- The
$mergestage writes the documents to thequarterlyreportcollection in the same database. If the stage finds an existing document in the collection that matches on the_idfield (the quarter), the stage merges the matching documents. Otherwise, the stage inserts the document.
Para visualizar os documentos na coleção quarterlyreport após os dados terem sido mesclados, execute a seguinte operação:
db.quarterlyreport.find().sort( { _id: 1 } )
A collection contém os seguintes documentos:
{ "_id" : "2019Q1", "sales" : 1950, "purchased" : 1200 } { "_id" : "2019Q2", "sales" : 500, "purchased" : 1700 }
Use o pipeline para personalizar a fusão
The $merge can use a custom update pipeline when documents match. The whenMatched pipeline can have the following stages:
$addFieldse seu alias$set$replaceRoote seu alias$replaceWith
Um exemplo de votes de coleta é preenchido com a contagem diária de votos. Cria a coleção com os seguintes documentos:
db.votes.insertMany( [ { date: new Date("2019-05-01"), "thumbsup" : 1, "thumbsdown" : 1 }, { date: new Date("2019-05-02"), "thumbsup" : 3, "thumbsdown" : 1 }, { date: new Date("2019-05-03"), "thumbsup" : 1, "thumbsdown" : 1 }, { date: new Date("2019-05-04"), "thumbsup" : 2, "thumbsdown" : 2 }, { date: new Date("2019-05-05"), "thumbsup" : 6, "thumbsdown" : 10 }, { date: new Date("2019-05-06"), "thumbsup" : 13, "thumbsdown" : 16 } ] )
Outra coleção de exemplo monthlytotals tem os totais de votos mensais atualizados. Cria a coleção com o seguinte documento:
db.monthlytotals.insertOne( { "_id" : "2019-05", "thumbsup" : 26, "thumbsdown" : 31 } )
No final de cada dia, os votos desse dia são inseridos na coleção votes:
db.votes.insertOne( { date: new Date("2019-05-07"), "thumbsup" : 14, "thumbsdown" : 10 } )
You can use $merge with an custom pipeline to update the existing document in the collection monthlytotals:
db.votes.aggregate([ { $match: { date: { $gte: new Date("2019-05-07"), $lt: new Date("2019-05-08") } } }, { $project: { _id: { $dateToString: { format: "%Y-%m", date: "$date" } }, thumbsup: 1, thumbsdown: 1 } }, { $merge: { into: "monthlytotals", on: "_id", whenMatched: [ { $addFields: { thumbsup: { $add:[ "$thumbsup", "$$new.thumbsup" ] }, thumbsdown: { $add: [ "$thumbsdown", "$$new.thumbsdown" ] } } } ], whenNotMatched: "insert" } } ])
- Primeiro estágio:
O estágio
$matchencontra os votos do dia específico. Por exemplo:{ "_id" : ObjectId("5ce6097c436eb7e1203064a6"), "date" : ISODate("2019-05-07T00:00:00Z"), "thumbsup" : 14, "thumbsdown" : 10 } - Segundo estágio:
O estágio
$projectdefine o campo_idcomo uma sequência de ano-mês. Por exemplo:{ "thumbsup" : 14, "thumbsdown" : 10, "_id" : "2019-05" } - Terceiro estágio:
The
$mergestage writes the documents to themonthlytotalscollection in the same database. If the stage finds an existing document in the collection that matches on the_idfield, the stage uses a pipeline to add thethumbsupvotes and thethumbsdownvotes.Esse pipeline não pode acessar diretamente os campos do documento de resultados. Para acessar o campo
thumbsupe o campothumbsdownno documento de resultados, o pipeline utiliza a variável$$new; ou seja,$$new.thumbsupe$new.thumbsdown.Este pipeline pode acessar diretamente o campo
thumbsupe o campothumbsdownno documento existente na coleção; ou seja,$thumbsupe$thumbsdown.
O documento resultante substitui o documento existente.
Para visualizar documentos na coleção monthlytotals após a operação de mesclagem, execute a seguinte operação:
db.monthlytotals.find()
A coleção contém o seguinte documento:
{ "_id" : "2019-05", "thumbsup" : 40, "thumbsdown" : 41 }
Usar variáveis para personalizar a fusão
You can use variables in the $merge stage whenMatched field. Variables must be defined before they can be used.
Defina variáveis em uma ou em ambas as opções a seguir:
Para usar variáveis em whenMatched:
Especifique o prefixo do sinal de dólar duplo ($$) juntamente com o nome da variável no formulário $$<variable_name>. Por exemplo, $$year. Se a variável estiver definida para um documento, você também poderá incluir um campo de documento no formulário $$<variable_name>.<field>. Por exemplo, $$year.month.
As guias abaixo demonstram o comportamento quando as variáveis são definidas no estágio de mesclagem, no comando de agregação ou em ambos.
Usar variáveis definidas no estágio de mesclagem
You can define variables in the $merge stage let and use the variables in the whenMatched field.
Exemplo:
db.cakeSales.insertOne( [ { _id: 1, flavor: "chocolate", salesTotal: 1580, salesTrend: "up" } ] ) db.runCommand( { aggregate: db.cakeSales.getName(), pipeline: [ { $merge: { into: db.cakeSales.getName(), let : { year: "2020" }, whenMatched: [ { $addFields: { "salesYear": "$$year" } } ] } } ], cursor: {} } ) db.cakeSales.find()
O exemplo:
cria uma coleção chamada
cakeSalesruns an
aggregatecommand that defines ayearvariable in the$mergelet and adds the year tocakeSalesusing whenMatchedretrieves the
cakeSalesdocument
Saída:
{ "_id" : 1, "flavor" : "chocolate", "salesTotal" : 1580, "salesTrend" : "up", "salesYear" : "2020" }
Usar variáveis definidas no comando de agregação
Novidade na versão 5.0.
You can define variables in the aggregate command let and use the variables in the $merge stage whenMatched field.
Exemplo:
db.cakeSales.insertOne( { _id: 1, flavor: "chocolate", salesTotal: 1580, salesTrend: "up" } ) db.runCommand( { aggregate: db.cakeSales.getName(), pipeline: [ { $merge: { into: db.cakeSales.getName(), whenMatched: [ { $addFields: { "salesYear": "$$year" } } ] } } ], cursor: {}, let : { year: "2020" } } ) db.cakeSales.find()
O exemplo:
cria uma coleção chamada
cakeSalesruns an
aggregatecommand that defines ayearvariable in theaggregatecommand let and adds the year tocakeSalesusing whenMatchedretrieves the
cakeSalesdocument
Saída:
{ "_id" : 1, "flavor" : "chocolate", "salesTotal" : 1580, "salesTrend" : "up", "salesYear" : "2020" }
Usar variáveis definidas no estágio de mesclagem e comando de agregação
You can define variables in the $merge stage and, starting in MongoDB 5.0, the aggregate command.
If two variables with the same name are defined in the $merge stage and the aggregate command, the $merge stage variable is used.
In this example, the year: "2020" $merge stage variable is used instead of the year: "2019" aggregate command variable:
db.cakeSales.insertOne( { _id: 1, flavor: "chocolate", salesTotal: 1580, salesTrend: "up" } ) db.runCommand( { aggregate: db.cakeSales.getName(), pipeline: [ { $merge: { into: db.cakeSales.getName(), let : { year: "2020" }, whenMatched: [ { $addFields: { "salesYear": "$$year" } } ] } } ], cursor: {}, let : { year: "2019" } } ) db.cakeSales.find()
Saída:
{ _id: 1, flavor: 'chocolate', salesTotal: 1580, salesTrend: 'up', salesYear: '2020' }
A classe Movie a seguir modela os documentos usados neste exemplo:
[] 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; } }
Para usar o driver MongoDB .NET/C# para adicionar um estágio $merge a uma agregação pipeline, chame o método UnionWith() em um objeto PipelineDefinition.
Ao chamar o Merge() método, você deve passar uma instância da classe MergeStageOptions . Este objeto permite especificar opções para o estágio $merge, como lidar com documentos correspondentes.
O exemplo a seguir cria um estágio de pipeline que mescla os documentos no pipeline na coleção movies. O objeto MergeStageOptions especifica as seguintes opções:
A opção
OnFieldNamesespecifica que a operação deve usar o campo"_id"para identificar documentos correspondentes.A opção
WhenMatchedespecifica que, se um documento na coleção de origem corresponder a um documento na coleção de destino, a operação substituirá o documento correspondente.A opção
WhenNotMatchedespecifica que, se um documento na coleção de origem não corresponder a um documento na coleção de destino, a operação inserirá o documento na coleção de destino.
var pipeline = new EmptyPipelineDefinition<Movie>() .Merge(_targetCollection, new MergeStageOptions<Movie>() { OnFieldNames = new List<string>() { "_id" }, WhenMatched = MergeStageWhenMatched.Replace, WhenNotMatched = MergeStageWhenNotMatched.Insert, });
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 $merge a um pipeline de agregação , use o operador $merge em um objeto de pipeline.
O exemplo a seguir cria um estágio de pipeline que mescla os documentos no pipeline na coleção movies. O exemplo inclui os seguintes campos:
A opção
onespecifica que a operação deve usar os campos"_id"e"title"para localizar documentos correspondentes na coleção de origem e na coleçãomovies.A opção
whenMatchedespecifica que, se um documento na coleção de origem corresponder a um documento na coleçãomovies, ele substituirá o documento na coleçãomovies.A opção
whenNotMatchedespecifica que, se um documento na collection de origem não corresponder a um documento na collectionmovies, a operação inserirá o documento na collectionmovies.
Em seguida, o exemplo executa o agregação pipeline:
const pipeline = [ { $merge: { into: "movies", on: ["_id", "title"], whenMatched: "replace", whenNotMatched: "insert" } } ]; const cursor = collection.aggregate(pipeline); return cursor;