Wenn Sie mit SQL vertraut sind, kennen Sie vielleicht die UNION
-Klausel, die die Ergebnisse zweier Abfragen zu einer einzigen Ergebnismenge verkettet. Insbesondere UNION ALL
enthält Duplikate.
In MongoDB können wir den $unionWith
verwenden Aggregation-Pipeline-Stufe, um den gleichen Effekt zu erzielen wie UNION ALL
produziert. Die $unionWith
stage führt eine Vereinigung von zwei Sammlungen durch – es kombiniert Pipeline-Ergebnisse aus zwei Sammlungen in einer einzigen Ergebnismenge. Und es enthält Duplikate.
Beispiel
Angenommen, wir erstellen zwei Sammlungen; eine namens cats
und eine andere namens dogs
. Und wir fügen die folgenden Dokumente in sie ein:
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 }
])
Wir können jetzt Abfragen für diese Sammlungen ausführen und den $unionWith
verwenden Stufe, um die Ergebnisse der einzelnen Abfragen zu kombinieren.
Beispiel:
db.cats.aggregate( [
{ $set: { _id: "$_id" } },
{ $unionWith: { coll: "dogs", pipeline: [ { $set: { _id: "$_id" } } ] } },
{ $sort: { type: 1, weight: -1, name: 1 } }
] )
Ergebnis:
{ "_id" :3, "name" :"Miau", "typ" :"Katze", "gewicht" :7 }{ "_id" :1, "name" :"Fluffy", "typ" :„Katze“, „Gewicht“ :5 }{ „_id“ :2, „Name“ :„Scratch“, „Typ“ :„Katze“, „Gewicht“ :3 }{ „_id“ :3, „Name“ :„Fluffy“, „Typ“ :„Hund“, „Gewicht“ :40 }{ „_id“ :1, „Name“ :„Wag“, „Typ“ :„Hund“, „Gewicht“ :20 }{ „ _id“ :2, „name“ :„Bark“, „type“ :„Hund“, „weight“ :10 }
In diesem Beispiel hat jedes Dokument ein Typfeld mit entweder cat
oder dog
und so ist ganz klar, welches Dokument aus welcher Sammlung stammt.
Wenn die Dokumente jedoch kein Typfeld hätten, wäre es schwieriger herauszufinden, wo eine Sammlung endet und eine andere beginnt. In diesem Fall können wir bei $set
ein String-Literal verwenden Bühne, um den Sammlungsnamen darzustellen.
Beispiel:
db.cats.aggregate( [
{ $set: { _id: "cat" } },
{ $unionWith: { coll: "dogs", pipeline: [ { $set: { _id: "dog" } } ] } },
{ $sort: { type: 1, weight: -1, name: 1 } }
] )
Ergebnis:
{ „_id“ :„cat“, „name“ :„Miau“, „type“ :„Cat“, „weight“ :7 }{ „_id“ :„cat“, „name“ :„Fluffy“ , „Typ“ :„Katze“, „Gewicht“ :5 }{ „_id“ :„Katze“, „Name“ :„Scratch“, „Typ“ :„Katze“, „Gewicht“ :3 }{ „_id“ :„Hund“, „Name“ :„Fluffy“, „Typ“ :„Hund“, „Gewicht“ :40 }{ „_id“ :„Hund“, „Name“ :„Wag“, „Typ“ :„Hund ", "Gewicht" :20 }{ "_id" :"Hund", "Name" :"Bell", "Typ" :"Hund", "Gewicht" :10 }
Sammlungsübergreifend sortieren
In den vorherigen Beispielen wurden die Katzen und die Hunde so sortiert, dass sie in zwei unterschiedliche Gruppen getrennt wurden; Erst Katzen, dann Hunde. Dies geschah hauptsächlich, weil wir nach type
sortiert haben Feld zuerst.
Aber wir können es nach jedem anderen Feld sortieren, was dazu führen könnte, dass Katzen und Hunde kombiniert werden.
Beispiel:
db.cats.aggregate( [
{ $set: { _id: "cat" } },
{ $unionWith: { coll: "dogs", pipeline: [ { $set: { _id: "dog" } } ] } },
{ $sort: { name: 1 } }
] )
Ergebnis:
{ "_id" :"dog", "name" :"Bark", "type" :"Hund", "weight" :10 }{ "_id" :"cat", "name" :"Fluffy" , „Typ“ :„Katze“, „Gewicht“ :5 }{ „_id“ :„Hund“, „Name“ :„Fluffy“, „Typ“ :„Hund“, „Gewicht“ :40 }{ „_id“ :„cat“, „name“ :„Meow“, „type“ :„Cat“, „weight“ :7 }{ „_id“ :„cat“, „name“ :„Scratch“, „type“ :„Cat ", "Gewicht" :3 }{ "_id" :"Hund", "Name" :"Wag", "Typ" :"Hund", "Gewicht" :20 }
Projektionen
Sie können das $project
verwenden stage, um anzugeben, welche Felder an die nächste Stufe in der Pipeline weitergegeben werden sollen. So können Sie beispielsweise die Anzahl der von der Abfrage zurückgegebenen Felder reduzieren.
Beispiel:
db.cats.aggregate( [
{ $project: { name: 1, _id: 0 } },
{ $unionWith: { coll: "dogs", pipeline: [ { $project: { name: 1, _id: 0 } } ]} }
] )
Ergebnis:
{ "name" :"Fluffy" }{ "name" :"Scratch" }{ "name" :"Miau" }{ "name" :"Wag" }{ "name" :"Bark" }{ " name" :"Fluffy" }
Duplikate entfernen
Sie können die $group
verwenden Stufe, um redundante Duplikate aus dem Ergebnis zu entfernen.
Die vorherige Abfrage hat beispielsweise zwei Haustiere namens Fluffy zurückgegeben. Wir können eine $group
hinzufügen Schritt zu dieser Abfrage, um das redundante Duplikat zu eliminieren, sodass nur ein Fluffy zurückgegeben wird.
db.cats.aggregate( [
{ $project: { name: 1, _id: 0 } },
{ $unionWith: { coll: "dogs", pipeline: [ { $project: { name: 1, _id: 0 } } ]} },
{ $group: { _id: "$name" } }
] )
Ergebnis:
{ "_id" :"Miau" }{ "_id" :"Bark" }{ "_id" :"Scratch" }{ "_id" :"Wag" }{ "_id" :"Fluffy" }Diesmal wird nur ein Fluffy zurückgegeben.
Nicht übereinstimmende Spalten
Einer der Vorteile von MongoDBs
$unionWith
hat überUNION ALL
von SQL ist, dass es mit nicht übereinstimmenden Spalten verwendet werden kann.Die SQL
UNION
-Klausel erfordert Folgendes:
- Beide Abfragen geben die gleiche Anzahl von Spalten zurück
- Die Spalten in derselben Reihenfolge
- Die übereinstimmenden Spalten müssen einen kompatiblen Datentyp haben
Die MongoDB $unionWith
Stage erlegt diese Beschränkungen nicht auf.
Daher könnten wir $unionWith
verwenden um so etwas zu tun:
db.cats.aggregate( [
{ $set: { _id: "$_id" } },
{ $unionWith: { coll: "employees", pipeline: [ { $set: { _id: "$_id" } } ] } },
{ $sort: { type: 1, salary: -1 } }
] )
Ergebnis:
{ "_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“ :„Fluffy ", "type" :"Cat", "weight" :5 }{ "_id" :2, "name" :"Scratch", "type" :"Cat", "weight" :3 }{ "_id" :3, „Name“ :„Miau“, „Typ“ :„Katze“, „Gewicht“ :7 }
In diesem Fall haben wir uns den cats
angeschlossen Sammlung mit den employees
Sammlung. Die employees
Die Sammlung hatte nicht die gleichen Felder wie die cats
Sammlung, aber das ist in Ordnung – es hat trotzdem funktioniert.