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

Esta página descreve o estágio$merge, que gera resultados do agregação pipeline para uma collection. Para o operador$mergeObjects, que mescla documentos em um único documento, consulte$mergeObjects.

$merge

Escreve os resultados do pipeline de agregação para uma coleção especificada. O operador $merge deve ser o último estágio no pipeline.

O $merge estágio:

  • Pode enviar para uma coleção no mesmo banco de dados ou em um banco de dados diferente.

  • Pode gerar saída para a mesma coleção que está sendo agregada. Para obter mais informações, consulte Saída para a mesma coleção que está sendo agregada.

  • Considere os seguintes pontos ao usar os $merge estágios ou em $out um agregação 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.

      • Nem todas as versões do driver suportam operações $merge enviadas aos nós secundários. Para obter detalhes, consulte a documentação do driver.

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

Para uma comparação com o estágio, que também gera os resultados da agregação em uma $out coleção,$merge $out consulte Comparação e .

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: o serviço totalmente gerenciado para implantações do MongoDB na nuvem
  • 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" } }

Se utilizar todas as opções padrão para, inclusive escrever em uma coleção no mesmo banco de dados, você poderá utilizar o formulário $merge simplificado:

{ $merge: <collection> } // Output collection is in the same database

O pega um documento com os seguintes $merge campos:

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

Se a coleta de saída não existir, o criará a$merge coleção:

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 requer um índice exclusivo com chaves que correspondam aos campos do identificador ligado. Embora a ordem da especificação da chave do índice não seja importante, o índice único deve conter apenas os on campos como suas chaves.

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

  • Se a coleção de saída não existir, o identificador on deverá ser e será padronizado para o _id campo . O índice exclusivo correspondente _id é criado automaticamente.

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

  • Se a coleção de saída existente for uma coleção fragmentada, o identificador ligado terá como padrão todos os campos de chave fragmentada e o _id campo. Se especificar um on identificador diferente, o on deverá conter todos os campos de chave de fragmento.

Opcional. O comportamento de se um documento de resultado e um documento $merge existente na coleção tiverem o mesmo valor para o(s) campo(s) especificado (s).

Você pode especificar:

  • Uma das strings de ação predefinidas:

    em ação
    Descrição

    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.

    Para evitar esse erro, se o campo on não incluir o _id campo, remova o _id campo nos resultados da agregação para evitar o erro, como em um $unset estágio de anterior e assim por diante.

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

    "merge" (Padrão)

    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.

    Para evitar esse erro, se o campo on não incluir o _id campo, remova o _id campo nos resultados da agregação para evitar o erro, como em um $unset estágio de anterior e assim por diante.

    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:

    O pipeline não pode modificar o valor do campo ligado. Por exemplo, se você estiver correspondendo no month campo, o pipeline não poderá modificar o month campo.

    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:

    • A variável $$new embutida para acessar o campo. Especificamente, $$new.<field>. A variável $$new só está disponível se a especificação let for omitida.

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

Se não for especificado,{ new: "$$ROOT" } ROOTo padrão será (consulte). O pipeline whenMatched pode acessar a $$new variável .

Para acessar as variáveis no pipeline 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.

Para obter exemplos, consulte Use Variables to Customize the Merge (Usar variáveis para personalizar a mesclagem).

Opcional. O comportamento de se um documento de resultado não corresponder a um documento existente na coleção de $merge saída.

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

em ação
Descrição

"insert" (Padrão)

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

Descarte o documento. Especificamente, o não insere o documento na coleção de$merge resultados.

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.

Se o _id campo não estiver presente em um documento dos resultados do pipeline de agregação , o estágio o gerará $merge automaticamente.

Por exemplo, no seguinte pipeline de agregação , exclui$project o _id campo dos documentos passados $merge para. Quando grava esses $merge documentos "newCollection" no, $merge gera um novo _id campo e valor.

db.sales.aggregate( [
{ $project: { _id: 0 } },
{ $merge : { into : "newCollection" } }
] )

A operação cria uma nova coleção se a coleção de saída especificada não $merge existir.

  • A coleção de saída é criada quando grava o primeiro documento na coleção e fica imediatamente $merge visível.

  • Se a agregação falhar, quaisquer gravações concluídas pelo antes do erro não serão $merge revertidas.

Observação

Para um conjunto de réplicas ou um autônomo, se o banco de dados de saída não existir, o também criará o banco de$merge dados.

Para um cluster fragmentado, o banco de dados de saída especificado já deve existir.

Se a coleção de saída não existir, $merge exigirá que o identificador on seja o _id campo. Para usar um on valor de campo diferente em uma coleção que não existe, você pode criar a coleção primeiro criando um índice único no(s) campo(s) desejado(s) primeiro. Por exemplo, se a coleção de saída newDailySales201905 não existir e você quiser especificar o salesDate campo como o identificador ligado:

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

O estágio$mergepode gerar saída para uma coleção fragmentada. Quando a coleção de saída é fragmentada, usa$mergeo _id campo e todos os campos de chave de fragmentação como o identificador padrão. Se você substituir o padrão, o identificador ativado deverá incluir todos os campos de chave do fragmento:

{ $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
);

A newrestaurants coleção conterá documentos com informações sobre aberturas de novos restaurantes por mês (date campo) e código postal (chave de shard); especificamente, o identificador ligado é ["date", "postcode"] (a ordem dos campos não importa). Como requer um índice único $merge com chaves que correspondam aos campos do identificador ligado, crie o índice único (a ordem dos campos não importa): []1

use exampledb
db.newrestaurants.createIndex( { postcode: 1, date: 1 }, { unique: true } )

Com a coleção fragmentada restaurants e o índice único criado, você pode usar $merge para gerar os resultados da agregação para essa coleção, correspondendo a,[ "date", "postcode" ] como neste exemplo:

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 pode substituir um documento existente na coleção de saída se os resultados da agregação contiverem um documento ou documentos que correspondam com base na especificação de . Como tal, pode substituir todos os documentos na$merge coleção existente se os resultados da agregação incluírem documentos correspondentes para todos os documentos existentes na coleção e você especificar "substituir" para whenMatched.

No entanto, para substituir uma coleção existente, independentemente dos resultados da agregação, use $out em vez disso.

Os $merge erros $merge _id do se o resultar em uma alteração no valor de um documento existente.

Dica

Para evitar esse erro, se o campo on não incluir o _id campo, remova o _id campo nos resultados da agregação para evitar o erro, como em um $unset estágio de anterior e assim por diante.

Além disso, para uma coleção fragmentada, $merge também gera um erro se resultar em uma alteração no valor da chave fragmentada de um documento existente.

As gravações concluídas pelo antes do erro não serão $merge revertidas.

Se o índice único usado por $merge para o(s) campo(s) for descartado no meio da agregação, não haverá garantias de que a agregação será eliminada. Se a agregação continuar, não haverá garantias de que os documentos não tenham on valores de campo duplicados.

Se o tentar gravar um documento que viole qualquer índice único na coleção de saída, a operação gerará um erro. Por $merge exemplo:

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:

  • O valor de whenMatched é um pipeline de agregação .

  • O valor de whenNotMatched inserté.

  • Não há correspondência para um documento na coleção de saída.

Com a introdução do, o $merge$merge $outMongoDB fornece duas etapas, e, para escrever os resultados do pipeline de agregação em uma coleção:

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

    Consulte$merge $outtambém Substituir documentos () vs Substituir coleção ().

  • 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$mergegera 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$mergealtera a localização física dos documentos armazenados no disco. Quando a localização física de um documento muda, $mergepode considerá-lo um documento totalmente novo , resultando em atualizações adicionais. Para obter mais informações sobre esse comportamento, consulte Problema de Halloween.

$merge pode gerar saída para a mesma coleção que está sendo agregada. Você também pode gerar saída para uma coleção que aparece em outros estágios do pipeline,$lookup como.

Restrições
Descrição

Um pipeline de agregação não pode usar dentro de $merge uma transação.

Um agregação pipeline não pode usar para gerar uma coleção de séries $merge temporais.

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

Uma definição de visualização não pode incluir o $merge estágio. Se a definição de visualização incluir pipeline aninhado (por exemplo, a definição de visualização inclui $facet o estágio), essa $merge restrição de estágio também se aplica aos pipelines aninhados.

$lookup estágio

O$lookupestágio do pipeline aninhado não pode incluir o estágio$merge.

$facet estágio

O$facetestágio do pipeline aninhado não pode incluir o estágio$merge.

$unionWith estágio

O$unionWithestágio do pipeline aninhado não pode incluir o estágio$merge.

"linearizable" Leia a preocupação

O estágio$mergenão pode ser usado em conjunto com preocupação de leitura"linearizable". Ou seja, se você especificar a preocupação de leitura"linearizable"paradb.collection.aggregate(), não poderá incluir o estágio$mergeno pipeline.

Se a coleta de saída não existir, o criará a $merge coleção.

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

Você pode usar os estágios $group e para criar inicialmente uma coleção chamada $merge budgets (no reporting banco de dados ) a partir dos dados atualmente na salaries coleção:

Observação

Para um conjunto de réplicas ou um sistema autônomo , se o banco de dados de saída não existir, o também criará o banco de$merge dados.

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 estágio $group grava a saída do estágio anterior na budgets coleção no reporting banco de dados.

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 gravar o conjunto de resultados na budgets coleção, substituindo documentos com o mesmo _id valor de (neste exemplo, um documento com o ano fiscal e o depto). Para documentos que não têm correspondências na coleção, insere os novos$merge documentos.

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 }

Para garantir que o não substitua os $merge dados existentes na coleção, defina whenMatched para keepExisting ou falhe.

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 Etapa para suprimir o _id campo e adicionar dept fiscal_year campo e separados. Quando os documentos são passados $merge para, gera automaticamente um$merge novo _id campo para os documentos.

  • $merge para escrever o resultado definido orgArchive para.

    O estágio faz $merge a correspondência dos documentos dept fiscal_year nos fails campos e quando houver correspondência. Ou seja, se já existir um documento para o mesmo departamento e ano fiscal, os $merge erros.

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 }

Se a coleção orgArchive já contiver um documento para 2019 para o departamento "A" e/ou "B", a agregação falhará devido ao erro de chave duplicada. No entanto, nenhum documento inserido antes do erro será revertido.

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.

Por padrão, se um documento nos resultados de agregação corresponder a um documento na coleção, a $merge etapa fundir os documentos.

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 }

Você pode usar o para mesclar os resultados $merge da purchaseorders coleção e da reportedsales coleção para criar uma nova quarterlyreport coleção.

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:
O estágio grava os documentos $merge na quarterlyreport coleção no mesmo banco de dados. Se o estágio encontrar um documento existente na coleção que corresponda ao _id campo, o estágio mesclará os documentos correspondentes. Caso contrário, o estágio insere o documento. Para a criação inicial, nenhum documento deve corresponder.

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:
O estágio grava os documentos $merge na quarterlyreport coleção no mesmo banco de dados. Se o estágio encontrar um documento existente na coleção que corresponda ao _id campo (o quarto), o estágio mesclará os documentos correspondentes. Caso contrário, o estágio insere o documento.

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 }

O pode $merge usar um pipeline de atualização personalizado quando os documentos correspondem. O pipeline whenMatched pode ter os seguintes estágios:

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

Você pode usar com um pipeline personalizado para atualizar o documento existente $merge na monthlytotals coleção:

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:

O estágio grava os documentos $merge na monthlytotals coleção no mesmo banco de dados. Se o estágio encontrar um documento existente na coleção que corresponda ao _id campo, o estágio usará um pipeline para adicionar os thumbsup votos e os thumbsdown votos.

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

Você pode usar variáveis no $merge campo stage whenMatched . As variáveis devem ser definidas antes de serem usadas.

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.

Você pode definir variáveis no $merge estágio let e usar as variáveis no campo whenMatched.

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

  • executa um comando que define aggregate uma year variável no $merge let e adiciona o ano a cakeSales usando WhenMatched

  • retrieves the cakeSales document

Saída:

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

Novidade na versão 5.0.

Você pode definir variáveis no aggregate comando let e usar as variáveis no $merge campo stage whenMatched .

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 cakeSales

  • executa um comando aggregate que define uma variável year no comando aggregate let e adiciona o ano a cakeSales usando WhenMatched

  • retrieves the cakeSales document

Saída:

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

Você pode definir variáveis no estágio e, começando no $merge MongoDB.,5 0o aggregate comando.

Se duas variáveis com o mesmo nome forem definidas no estágio $merge e no comando,aggregate $merge a variável de estágio será usada.

Neste exemplo, a year: "2020" $merge variável de estágio é usada em vez da year: "2019" aggregate variável de comando:

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:

[BsonIgnoreExtraElements]
public class Movie
{
[BsonId]
public ObjectId Id { get; set; }
[BsonElement("title")]
public string Title { get; set; } = null!;
[BsonElement("year")]
public int? Year { get; set; }
[BsonElement("runtime")]
public int? Runtime { get; set; }
[BsonElement("rated")]
public string? Rated { get; set; }
[BsonElement("metacritic")]
public int Metacritic { get; set; }
[BsonElement("plot")]
public string? Plot { get; set; }
[BsonElement("type")]
public string? Type { get; set; }
[BsonElement("cast")]
public string[]? Cast { get; set; }
[BsonElement("directors")]
public string[]? Directors { get; set; }
[BsonElement("writers")]
public string[]? Writers { get; set; }
[BsonElement("imdb")]
public ImdbData? Imdb { get; set; }
}

Para usar o driver MongoDB .NET/C# para adicionar um $merge estágio a uma agregação pipeline, chame o método unionWith() em um PipelineDefinition objeto.

Ao chamar o Merge() método, você deve passar uma instância da classe MergeStageOptions . Este objeto permite especificar opções para o $merge estágio, 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 OnFieldNames especifica que a operação deve usar o campo "_id" para identificar documentos correspondentes.

  • A opção WhenMatched especifica 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 WhenNotMatched especifica 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,
});
{ "_id": "...", "title": "Back to the Future", "metacritic": 96 }
{ "_id": "...", "title": "Jurassic Park", "metacritic": 68 }
{ "_id": "...", "title": "The Shawshank Redemption", "metacritic": 80 }

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 on especifica que a operação deve usar os campos "_id" e "title" para localizar documentos correspondentes na coleção de origem e na coleção movies.

  • A opção whenMatched especifica que, se um documento na coleção de origem corresponder a um documento na coleção movies, ele substituirá o documento na coleção movies.

  • A opção whenNotMatched especifica que, se um documento na collection de origem não corresponder a um documento na collection movies, a operação inserirá o documento na collection movies.

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;