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.