Pokud jste obeznámeni s SQL, možná znáte UNION
klauzule, která zřetězí výsledky dvou dotazů do jediné sady výsledků. Konkrétně UNION ALL
zahrnuje duplikáty.
V MongoDB můžeme použít $unionWith
agregační fáze potrubí k dosažení stejného efektu jako UNION ALL
vyrábí. $unionWith
stage provádí spojení dvou kolekcí – kombinuje výsledky z potrubí ze dvou kolekcí do jediné sady výsledků. A zahrnuje duplikáty.
Příklad
Předpokládejme, že vytvoříme dvě kolekce; jeden s názvem cats
a další s názvem dogs
. A vložíme do nich následující dokumenty:
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 }
])
Nyní můžeme spustit dotazy na tyto kolekce a použít $unionWith
fázi ke kombinaci výsledků každého dotazu.
Příklad:
db.cats.aggregate( [
{ $set: { _id: "$_id" } },
{ $unionWith: { coll: "dogs", pipeline: [ { $set: { _id: "$_id" } } ] } },
{ $sort: { type: 1, weight: -1, name: 1 } }
] )
Výsledek:
{ "_id" :3, "name" :"Mňau", "type" :"Kočka", "váha" :7 }{ "_id" :1, "name" :"Fluffy", "type" :"Kočka", "váha" :5 }{ "_id" :2, "jméno" :"Scratch", "type" :"Kočka", "váha" :3 }{ "_id" :3, "jméno" :"Fluffy", "type" :"Pes", "váha" :40 }{ "_id" :1, "name" :"Wag", "type" :"Pes", "váha" :20 }{ " _id" :2, "name" :"Štěkání", "type" :"Pes", "váha" :10 }
V tomto příkladu má každý dokument pole typu s buď cat
nebo dog
a tak je zcela zřejmé, který dokument pochází z které sbírky.
Pokud by však dokumenty neměly pole typu, bylo by těžší zjistit, kde jedna kolekce končí a druhá začíná. V tomto případě můžeme použít řetězcový literál v $set
fázi reprezentující název kolekce.
Příklad:
db.cats.aggregate( [
{ $set: { _id: "cat" } },
{ $unionWith: { coll: "dogs", pipeline: [ { $set: { _id: "dog" } } ] } },
{ $sort: { type: 1, weight: -1, name: 1 } }
] )
Výsledek:
{ "_id" :"cat", "name" :"Mňau", "type" :"Kočka", "váha" :7 }{ "_id" :"cat", "name" :"Fluffy" , "type" :"Kočka", "váha" :5 }{ "_id" :"kočka", "jméno" :"Scratch", "type" :"Kočka", "váha" :3 }{ "_id" :"pes", "name" :"Fluffy", "type" :"Pes", "váha" :40 }{ "_id" :"pes", "name" :"Wag", "type" :"Pes" ", "váha" :20 }{ "_id" :"pes", "jméno" :"Štěkání", "typ" :"Pes", "váha" :10 }
Řazení napříč kolekcemi
V předchozích příkladech byli kočky a psi roztříděni způsobem, který je rozděloval do dvou odlišných skupin; nejprve kočky, pak psi. Stalo se to hlavně proto, že jsme třídili podle type
pole jako první.
Ale můžeme to třídit na jakémkoli jiném poli, což by mohlo vést ke spojení koček a psů.
Příklad:
db.cats.aggregate( [
{ $set: { _id: "cat" } },
{ $unionWith: { coll: "dogs", pipeline: [ { $set: { _id: "dog" } } ] } },
{ $sort: { name: 1 } }
] )
Výsledek:
{ "_id" :"pes", "name" :"Štěkání", "type" :"Pes", "váha" :10 }{ "_id" :"kočka", "jméno" :"Načechraný" , "type" :"Kočka", "váha" :5 }{ "_id" :"pes", "name" :"Fluffy", "type" :"Pes", "váha" :40 }{ "_id" :"kočka", "jméno" :"Mňau", "typ" :"Kočka", "váha" :7 }{ "_id" :"kočka", "jméno" :"Scratch", "type" :"Kočka ", "váha" :3 }{ "_id" :"pes", "name" :"Wag", "type" :"Pes", "váha" :20 }
Projekce
Můžete použít $project
fázi k určení, která pole mají být předána do další fáze v potrubí. Můžete tak například snížit počet polí vrácených dotazem.
Příklad:
db.cats.aggregate( [
{ $project: { name: 1, _id: 0 } },
{ $unionWith: { coll: "dogs", pipeline: [ { $project: { name: 1, _id: 0 } } ]} }
] )
Výsledek:
{ "name" :"Fluffy" }{ "name" :"Scratch" }{ "name" :"Mňau" }{ "name" :"Wag" }{ "name" :"Bark" }{ " jméno" :"Načechraný" }
Odstranit duplikáty
Můžete použít $group
fázi k odstranění nadbytečných duplikátů z výsledku.
Například předchozí dotaz vrátil dva mazlíčky s názvem Fluffy. Můžeme přidat $group
fázi k tomuto dotazu, abyste odstranili nadbytečný duplikát, takže je vrácen pouze jeden Fluffy.
db.cats.aggregate( [
{ $project: { name: 1, _id: 0 } },
{ $unionWith: { coll: "dogs", pipeline: [ { $project: { name: 1, _id: 0 } } ]} },
{ $group: { _id: "$name" } }
] )
Výsledek:
{ "_id" :"Mňau" }{ "_id" :"Štěkat" }{ "_id" :"Škrábnutí" }{ "_id" :"Wag" }{ "_id" :"Načechraný" }Tentokrát je vrácen pouze jeden Fluffy.
Neodpovídající sloupce
Jedna z výhod MongoDB
$unionWith
má více než SQLUNION ALL
je, že jej lze použít s neodpovídajícími sloupci.SQL
UNION
klauzule vyžaduje, aby:
- Oba dotazy vracejí stejný počet sloupců
- Sloupce ve stejném pořadí
- Odpovídající sloupce musí mít kompatibilní datový typ
MongoDB $unionWith
fáze tato omezení neukládá.
Proto bychom mohli použít $unionWith
udělat něco takového:
db.cats.aggregate( [
{ $set: { _id: "$_id" } },
{ $unionWith: { coll: "employees", pipeline: [ { $set: { _id: "$_id" } } ] } },
{ $sort: { type: 1, salary: -1 } }
] )
Výsledek:
{ "_id" :2, "jméno" :"Sarah", "plat" :128000 }{ "_id" :5, "jméno" :"Beck", "plat" :82000 }{ "_id" :4, "jméno" :"Chris", "plat" :45000 }{ "_id" :3, "jméno" :"Fritz", "plat" :25000 }{ "_id" :1, "jméno" :"Fluffy ", "type" :"Kočka", "váha" :5 }{ "_id" :2, "name" :"Scratch", "type" :"Kočka", "váha" :3 }{ "_id" :3, "jméno" :"Mňau", "typ" :"Kočka", "váha" :7 }
V tomto případě jsme se připojili k cats
sběr s employees
sbírka. employees
kolekce neměla stejná pole jako cats
kolekce, ale to je v pořádku – stále to fungovalo.