Para agentes de IA: um índice de documentação está disponível em https://www.mongodb.com/pt-br/docs/llms.txt — as versões de markdown de todas as páginas estão disponíveis anexando .md a qualquer caminho de URL.
Menu Docs

$merge (estágio de agregaçã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.

$merge

Writes the results of the aggregation pipeline to a specified collection. The $merge operator must be the last stage in the pipeline.

The $merge stage:

  • 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 $merge or $out stages in an aggregation pipeline:

    • A partir do MongoDB 5.0, os pipelines com um estágio $merge poderão ser executados em nós secundários do conjunto de réplicas se todos os nós do cluster tiverem o featureCompatibilityVersion definido como 5.0 ou superior e a preferência de leitura permitir leituras secundárias.

      • $merge e os estágios $out são executados em nós secundários, mas as operações de gravação são enviadas para o nó primário.

      • Not all driver versions support $merge operations sent to the secondary nodes. For details, see the driver documentation.

    • nas versões anteriores do MongoDB , os pipelines com estágios $out ou $merge sempre 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 $out stage which also outputs the aggregation results to a collection, see $merge and $out Comparison.

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.

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

$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:

  • O nome da coleção como uma string para saída para uma coleção no mesmo banco de dados onde a agregação é executada. Por exemplo:

    into: "myOutput"

  • O nome do banco de dados e da coleção em um documento para saída para uma coleção no banco de dados especificado. Por exemplo:

    into: { db:"myDB", coll:"myOutput" }

If the output collection does not exist, $merge creates the collection:

  • 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.

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:

  • Um único nome de campo como uma string. Por exemplo:

    on: "_id"

  • Uma combinação de campos em uma array. Por exemplo:

    on: [ "date", "customerId" ]

    A ordem dos campos na array não importa, e você não pode especificar o mesmo campo várias vezes.

Para o campo ou campos especificados:

  • Os documentos de resultados da agregação devem conter o(s) campo(s) especificado(s) em on, a menos que o campo on seja o campo _id. Se o campo _id estiver faltando em um documento de resultados, o MongoDB o adicionará automaticamente.

  • O campo ou campos especificados não podem conter um valor de array ou nulo.

$merge requires a unique, index with keys that correspond to the on identifier fields. Although the order of the index key specification does not matter, the unique index must only contain the on fields as its keys.

  • O índice também deve ter o mesmo agrupamento que o agrupamento da agregação.

  • O índice exclusivo pode ser um índice esparso .

  • O índice único não pode ser um índice parcial.

  • Para coleções de saída que já existem, o índice correspondente já deve existir.

O valor padrão para ativado depende da coleção de saída:

  • If the output collection does not exist, the on identifier must be and defaults to the _id field. The corresponding unique _id index is automatically created.

    • Para usar um campo de identificador diferente em uma coleção que não existe, você pode criar a coleção primeiro, criando um índice exclusivo no(s) campo(s) desejado(s). Consulte a seção sobre coleção de saída inexistente para obter um exemplo.
  • Se a coleção de saída existente não estiver fragmentada, o identificador on assumirá como padrão o campo _id.

  • If the existing output collection is a sharded collection, the on identifier defaults to all the shard key fields and the _id field. If specifying a different on identifier, the on must contain all the shard key fields.

Optional. The behavior of $merge if a result document and an existing document in the collection have the same value for the specified on field(s).

Você pode especificar:

  • Uma das strings de ação predefinidas:

    • "substituir":

      Substitua o documento existente na coleção de resultados pelo documento de resultados correspondente.

      Ao executar uma substituição, o documento de substituição não pode resultar em uma modificação do valor _id ou, se a coleção de saída for fragmentada, o valor da chave de estilhaço. Caso contrário, a operação gera um erro.

      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.

    • "keepExisting":

      Mantenha o documento existente na coleção de resultados.

    • "merge" (Default):

      Mesclar os documentos correspondentes (semelhante ao operador $mergeObjects).

      • Se o documento de resultados contiver campos que não estejam no documento existente, adicione esses novos campos ao documento existente.

      • Se o documento de resultados contiver campos no documento existente, substitua os valores de campo existentes pelos valores do documento de resultados.

      Por exemplo, se a coleção de saída tiver o documento:

      { _id: 1, a: 1, b: 1 }

      E os resultados da agregação tiverem o documento:

      { _id: 1, b: 5, z: 1 }

      Em seguida, o documento mesclado é:

      { _id: 1, a: 1, b: 5, z: 1 }

      Ao realizar uma mesclagem, o documento mesclado não pode resultar em uma modificação do valor _id ou, se a coleção de saída for fragmentada, do valor da chave fragmentada. Caso contrário, a operação gera um erro.

      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.

    • "falha":

      Pare e falhe a operação de agregação. Quaisquer alterações na coleção de saída de documentos anteriores não serão revertidas.

  • Um pipeline de agregação para atualizar o documento na coleção.

    [ <stage1>, <stage2> ... ]

    O pipeline só pode consistir nas seguintes etapas:

    The pipeline cannot modify the on field's value. For example, if you are matching on the field month, the pipeline cannot modify the month field.

    O whenMatched pipeline pode acessar diretamente os campos dos documentos existentes na coleção de saída utilizando $<field>.

    Para acessar os campos a partir dos documentos de resultados de agregação, use:

    • The built-in $$new variable to access the field. Specifically, $$new.<field>. The $$new variable is only available if the let specification is omitted.

    • As variáveis definidas pelo usuário no campo let.

      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.

      Para obter mais exemplos, consulte Usar variáveis para personalizar a fusão.

Opcional. Especifica variáveis para uso no pipeline whenMatched.

Especifique um documento com os nomes de variáveis e expressões de valor:

{ <variable_name_1>: <expression_1>,
...,
<variable_name_n>: <expression_n> }

If unspecified, defaults to { new: "$$ROOT" } (see ROOT). The whenMatched pipeline can access the $$new variable.

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 $$<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.

For examples, see Use Variables to Customize the Merge.

Optional. The behavior of $merge if a result document does not match an existing document in the out collection.

Você pode especificar uma das strings de ação predefinidas:

  • "insert" (Default):

    Insira o documento na coleção de saída.

  • "descartar":

    Discard the document. Specifically, $merge does not insert the document into the output collection.

  • "falha":

    Pare e falhe a operação de agregação. Quaisquer alterações já gravadas na coleção de saída não serão revertidas.

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

The $merge operation creates a new collection if the specified output collection does not exist.

  • The output collection is created when $merge writes the first document into the collection and is immediately visible.

  • If the aggregation fails, any writes completed by the $merge before 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" } }
] )

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 sh.shardCollection() também pode criar um índice único na chave de shard com hash quando a opção { unique: true } for passada se: a chave de shard com hash for baseada em faixa, a coleção estiver vazia e um índice único na chave de shard com hash ainda não existir.

No exemplo anterior, como o identificador on é a chave de shard com hash e outro campo, é necessária uma operação separada para criar o índice correspondente.

$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.

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.

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:

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.

$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.

With the introduction of $merge, MongoDB provides two stages, $merge and $out, for writing the results of the aggregation pipeline to a collection:

  • Pode enviar para uma coleção no mesmo banco de dados ou em um banco de dados diferente.
  • Pode enviar para uma coleção no mesmo banco de dados ou em um banco de dados diferente.
  • Cria uma nova coleta se a coleta de saída ainda não existir.
  • 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.

    See also Replace Documents ($merge) vs Replace Collection ($out).

  • Substitui completamente a coleção de saída se ela já existir.
  • Pode gerar saída para uma coleção fragmentada. A coleta de entrada também pode ser fragmentada.
  • Não é possível gerar saída para uma coleção fragmentada. A coleção de entrada, no entanto, pode ser fragmentada.
  • Corresponde a declarações SQL:

    • MERGE.

    • INSERT INTO T2 SELECT FROM T1.

    • SELECT INTO T2 FROM T1.

    • Criar/Atualizar visualizações materializadas.

  • Corresponde à declaração SQL:

    • INSERT INTO T2 SELECT FROM T1.

    • SELECT INTO T2 FROM T1.

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
Descrição

An aggregation pipeline cannot use $merge inside a transaction.

An aggregation pipeline cannot use $merge to output to a time series collection.

ver definição
Separar da exibição materializada

A view definition cannot include the $merge stage. If the view definition includes nested pipeline (for example, the view definition includes $facet stage), this $merge stage restriction applies to the nested pipelines as well.

$lookup estágio

$lookup stage's nested pipeline cannot include the $merge stage.

$facet estágio

$facet stage's nested pipeline cannot include the $merge stage.

$unionWith estágio

$unionWith stage's nested pipeline cannot include the $merge stage.

"linearizable" Leia a preocupação

The $merge stage cannot be used in conjunction with read concern "linearizable". That is, if you specify "linearizable" read concern for db.collection.aggregate(), you cannot include the $merge stage in the pipeline.

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 $group para agrupar os salários por fiscal_year e dept.

  • $merge stage writes the output of the preceding $group stage to the budgets collection in the reporting database.

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 }

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:

  • $match etapa para encontrar todos os documentos com fiscal_year maior ou igual a 2019.

  • Etapa $group para agrupar os salários por fiscal_year e dept.

  • $merge to write the result set to the budgets collection, replacing documents with the same _id value (in this example, a document with the fiscal year and dept). For documents that do not have matches in the collection, $merge inserts 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 }

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 $match para encontrar todos os documentos com fiscal_year igual a 2019.

  • $group estágio para agrupar os funcionários por fiscal_year e dept.

  • $project stage to suppress the _id field and add separate dept and fiscal_year field. When the documents are passed to $merge, $merge automatically generates a new _id field for the documents.

  • $merge to write the result set to orgArchive.

    The $merge stage matches documents on the dept and fiscal_year fields and fails when matched. That is, if a document already exists for the same department and fiscal year, the $merge errors.

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.

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 $group agrupa por trimestre e usa $sum para adicionar os campos qty em um novo campo purchased. 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 $merge stage writes the documents to the quarterlyreport collection in the same database. If the stage finds an existing document in the collection that matches on the _id field, 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 $group agrupa por trimestre e usa $sum para adicionar os campos qty em um novo campo sales. Por exemplo:

{ "_id" : "2019Q2", "sales" : 500 }
{ "_id" : "2019Q1", "sales" : 1950 }
Segundo estágio:
The $merge stage writes the documents to the quarterlyreport collection in the same database. If the stage finds an existing document in the collection that matches on the _id field (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 }

The $merge can use a custom update pipeline when documents match. The whenMatched pipeline can have the following stages:

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 $match encontra 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 $project define o campo _id como uma sequência de ano-mês. Por exemplo:

{ "thumbsup" : 14, "thumbsdown" : 10, "_id" : "2019-05" }
Terceiro estágio:

The $merge stage writes the documents to the monthlytotals collection in the same database. If the stage finds an existing document in the collection that matches on the _id field, the stage uses a pipeline to add the thumbsup votes and the thumbsdown votes.

  • Esse pipeline não pode acessar diretamente os campos do documento de resultados. Para acessar o campo thumbsup e o campo thumbsdown no documento de resultados, o pipeline utiliza a variável $$new; ou seja, $$new.thumbsup e $new.thumbsdown.

  • Este pipeline pode acessar diretamente o campo thumbsup e o campo thumbsdown no documento existente na coleção; ou seja, $thumbsup e $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 }

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.

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 cakeSales

  • runs an aggregate command that defines a year variable in the $merge let and adds the year to cakeSales using whenMatched

  • retrieves the cakeSales document

Saída:

{ "_id" : 1, "flavor" : "chocolate", "salesTotal" : 1580,
"salesTrend" : "up", "salesYear" : "2020" }