MongoDB
 sql >> Base de Dados >  >> NoSQL >> MongoDB

$unionWith – Equivalente de UNION ALL no MongoDB


Se você estiver familiarizado com SQL, talvez conheça o UNION cláusula, que concatena os resultados de duas consultas em um único conjunto de resultados. Em particular, UNION ALL inclui duplicatas.

No MongoDB, podemos usar o $unionWith estágio de pipeline de agregação para obter o mesmo efeito que UNION ALL produz. O $unionWith stage realiza uma união de duas coleções – combina os resultados do pipeline de duas coleções em um único conjunto de resultados. E inclui duplicatas.

Exemplo


Suponha que criamos duas coleções; um chamado cats e outro chamado dogs . E inserimos os seguintes documentos neles:
db.cats.insertMany([
    { _id: 1, name: "Fluffy", type: "Cat", weight: 5 },
    { _id: 2, name: "Scratch", type: "Cat", weight: 3 },
    { _id: 3, name: "Meow", type: "Cat", weight: 7 }
    ])

db.dogs.insertMany([
    { _id: 1, name: "Wag", type: "Dog", weight: 20 },
    { _id: 2, name: "Bark", type: "Dog", weight: 10 },
    { _id: 3, name: "Fluffy", type: "Dog", weight: 40 }
    ]) 

Agora podemos executar consultas nessas coleções e usar o $unionWith etapa para combinar os resultados de cada consulta.

Exemplo:
db.cats.aggregate( [
   { $set: { _id: "$_id" } },
   { $unionWith: { coll: "dogs", pipeline: [ { $set: { _id: "$_id" } } ] } },
   { $sort: { type: 1, weight: -1, name: 1 } }
] ) 

Resultado:
{ "_id" :3, "name" :"Miau", "type" :"Gato", "peso" :7 }{ "_id" :1, "name" :"Fofo", "tipo" :"Cat", "weight" :5 }{ "_id" :2, "name" :"Scratch", "type" :"Cat", "weight" :3 }{ "_id" :3, "name" :"Fluffy", "type" :"Dog", "weight" :40 }{ "_id" :1, "name" :"Wag", "type" :"Dog", "weight" :20 }{ " _id" :2, "name" :"Latido", "type" :"Cão", "peso" :10 }

Neste exemplo, cada documento tem um campo de tipo com cat ou dog e, portanto, é bastante aparente qual documento vem de qual coleção.

Mas se os documentos não tivessem o campo de tipo, seria mais difícil descobrir onde uma coleção termina e outra começa. Neste caso, podemos usar uma string literal no $set stage para representar o nome da coleção.

Exemplo:
db.cats.aggregate( [
   { $set: { _id: "cat" } },
   { $unionWith: { coll: "dogs", pipeline: [ { $set: { _id: "dog" } } ] } },
   { $sort: { type: 1, weight: -1, name: 1 } }
] ) 

Resultado:
{ "_id" :"cat", "name" :"Miau", "type" :"Cat", "weight" :7 }{ "_id" :"cat", "name" :"Fofo" , "type" :"Cat", "weight" :5 }{ "_id" :"cat", "name" :"Scratch", "type" :"Cat", "weight" :3 }{ "_id" :"cachorro", "name" :"Fofo", "type" :"Cachorro", "peso" :40 }{ "_id" :"cachorro", "name" :"Wag", "type" :"Cachorro ", "weight" :20 }{ "_id" :"dog", "name" :"Latido", "type" :"Dog", "weight" :10 }

Classificação entre coleções


Nos exemplos anteriores, os gatos e os cães foram classificados de forma a separá-los em dois grupos distintos; gatos primeiro, depois cachorros. Isso aconteceu principalmente porque classificamos no type campo primeiro.

Mas podemos classificá-lo em qualquer outro campo, o que pode resultar na combinação de cães e gatos.

Exemplo:
db.cats.aggregate( [
   { $set: { _id: "cat" } },
   { $unionWith: { coll: "dogs", pipeline: [ { $set: { _id: "dog" } } ] } },
   { $sort: { name: 1 } }
] ) 

Resultado:
{ "_id" :"cachorro", "name" :"Latido", "tipo" :"Cachorro", "peso" :10 }{ "_id" :"gato", "name" :"Fofo" , "type" :"Cat", "weight" :5 }{ "_id" :"dog", "name" :"Fluffy", "type" :"Dog", "weight" :40 }{ "_id" :"cat", "name" :"Miau", "type" :"Cat", "weight" :7 }{ "_id" :"cat", "name" :"Scratch", "type" :"Cat ", "weight" :3 }{ "_id" :"dog", "name" :"Wag", "type" :"Dog", "weight" :20 }

Projeções


Você pode usar o $project stage para especificar quais campos devem ser passados ​​para o próximo estágio no pipeline. Por exemplo, você pode reduzir o número de campos retornados pela consulta.

Exemplo:
db.cats.aggregate( [
   { $project: { name: 1, _id: 0 } },
   { $unionWith: { coll: "dogs", pipeline: [ { $project: { name: 1, _id: 0 } } ]} }
] ) 

Resultado:
{ "name" :"Fofo" }{ "name" :"Scratch" }{ "name" :"Miau" }{ "name" :"Wag" }{ "name" :"Latido" }{ " name" :"Fofo" }

Remover duplicatas


Você pode usar o $group etapa para eliminar duplicatas redundantes do resultado.

Por exemplo, a consulta anterior retornou dois animais de estimação chamados Fluffy. Podemos adicionar um $group stage para essa consulta para eliminar a duplicata redundante, de modo que apenas um Fluffy seja retornado.
db.cats.aggregate( [
   { $project: { name: 1, _id: 0 } },
   { $unionWith: { coll: "dogs", pipeline: [ { $project: { name: 1, _id: 0 } } ]} },
   { $group: { _id: "$name" } }
] ) 

Resultado:
{ "_id" :"Miau" }{ "_id" :"Bark" }{ "_id" :"Scratch" }{ "_id" :"Wag" }{ "_id" :"Fofo" } 
Desta vez, apenas um Fluffy é retornado.

Colunas não correspondentes


Uma das vantagens que o $unionWith do MongoDB tem sobre o UNION ALL do SQL é que ele pode ser usado com colunas não correspondentes.

O SQL UNION cláusula exige que:
  • Ambas as consultas retornam o mesmo número de colunas
  • As colunas na mesma ordem
  • As colunas correspondentes devem ser de um tipo de dados compatível

O MongoDB $unionWith palco não impõe essas limitações.

Portanto, podemos usar $unionWith para fazer algo assim:
db.cats.aggregate( [
   { $set: { _id: "$_id" } },
   { $unionWith: { coll: "employees", pipeline: [ { $set: { _id: "$_id" } } ] } },
   { $sort: { type: 1, salary: -1 } }
] ) 

Resultado:
{ "_id" :2, "name" :"Sarah", "salary" :128000 }{ "_id" :5, "name" :"Beck", "salary" :82000 }{ "_id" :4, "name" :"Chris", "salary" :45000 }{ "_id" :3, "name" :"Fritz", "salary" :25000 }{ "_id" :1, "name" :"Fofo ", "type" :"Cat", "weight" :5 }{ "_id" :2, "name" :"Scratch", "type" :"Cat", "weight" :3 }{ "_id" :3, "name" :"Miau", "type" :"Gato", "peso" :7 }

Neste caso, juntamos os cats coleção com os employees coleção. Os employees coleção não tinha os mesmos campos que os cats coleção, mas tudo bem – ainda funcionou.