Si vous êtes familier avec SQL, vous connaissez peut-être l'UNION
clause, qui concatène les résultats de deux requêtes en un seul jeu de résultats. En particulier, UNION ALL
inclut les doublons.
Dans MongoDB, nous pouvons utiliser le $unionWith
étape de pipeline d'agrégation pour obtenir le même effet que UNION ALL
produit. Le $unionWith
stage effectue une union de deux collections - il combine les résultats du pipeline de deux collections en un seul ensemble de résultats. Et cela inclut les doublons.
Exemple
Supposons que nous créons deux collections ; un appelé cats
et un autre appelé dogs
. Et nous y insérons les documents suivants :
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 }
])
Nous pouvons maintenant exécuter une requête sur ces collections et utiliser le $unionWith
étape pour combiner les résultats de chaque requête.
Exemple :
db.cats.aggregate( [
{ $set: { _id: "$_id" } },
{ $unionWith: { coll: "dogs", pipeline: [ { $set: { _id: "$_id" } } ] } },
{ $sort: { type: 1, weight: -1, name: 1 } }
] )
Résultat :
{ "_id" :3, "name" :"Meow", "type" :"Chat", "weight" :7 }{ "_id" :1, "name" :"Fluffy", "type" :"Chat", "poids" :5 }{ "_id" :2, "nom" :"Scratch", "type" :"Chat", "poids" :3 }{ "_id" :3, "nom" :"Fluffy", "type" :"Chien", "weight" :40 }{ "_id" :1, "name" :"Wag", "type" :"Chien", "weight" :20 }{ " _id" :2, "name" :"Bark", "type" :"Chien", "weight" :10 }
Dans cet exemple, chaque document a un champ de type avec soit cat
ou dog
et il est donc tout à fait évident quel document provient de quelle collection.
Mais si les documents n'avaient pas le champ de type, il serait alors plus difficile de déterminer où une collection se termine et une autre commence. Dans ce cas, nous pouvons utiliser un littéral de chaîne au $set
stage pour représenter le nom de la collection.
Exemple :
db.cats.aggregate( [
{ $set: { _id: "cat" } },
{ $unionWith: { coll: "dogs", pipeline: [ { $set: { _id: "dog" } } ] } },
{ $sort: { type: 1, weight: -1, name: 1 } }
] )
Résultat :
{ "_id" :"cat", "name" :"Meow", "type" :"Cat", "weight" :7 }{ "_id" :"cat", "name" :"Fluffy" , "type" :"Chat", "poids" :5 }{ "_id" :"chat", "nom" :"Scratch", "type" :"Chat", "poids" :3 }{ "_id" :"dog", "name" :"Fluffy", "type" :"Chien", "weight" :40 }{ "_id" :"dog", "name" :"Wag", "type" :"Chien ", "weight" :20 }{ "_id" :"dog", "name" :"Bark", "type" :"Chien", "weight" :10 }
Trier les collections
Dans les exemples précédents, les chats et les chiens étaient triés de manière à les séparer en deux groupes distincts; les chats d'abord, puis les chiens. Cela s'est produit principalement parce que nous avons trié sur le type
champ en premier.
Mais nous pouvons le trier sur n'importe quel autre champ, ce qui pourrait entraîner la combinaison des chats et des chiens.
Exemple :
db.cats.aggregate( [
{ $set: { _id: "cat" } },
{ $unionWith: { coll: "dogs", pipeline: [ { $set: { _id: "dog" } } ] } },
{ $sort: { name: 1 } }
] )
Résultat :
{ "_id" :"dog", "name" :"Bark", "type" :"Chien", "weight" :10 }{ "_id" :"cat", "name" :"Fluffy" , "type" :"Chat", "weight" :5 }{ "_id" :"dog", "name" :"Fluffy", "type" :"Chien", "weight" :40 }{ "_id" :"chat", "nom" :"Miaou", "type" :"Chat", "poids" :7 }{ "_id" :"chat", "nom" :"Scratch", "type" :"Chat ", "weight" :3 }{ "_id" :"chien", "name" :"Wag", "type" :"Chien", "weight" :20 }
Projections
Vous pouvez utiliser le $project
étape pour spécifier quels champs doivent être transmis à l'étape suivante du pipeline. Par exemple, vous pouvez ainsi réduire le nombre de champs renvoyés par la requête.
Exemple :
db.cats.aggregate( [
{ $project: { name: 1, _id: 0 } },
{ $unionWith: { coll: "dogs", pipeline: [ { $project: { name: 1, _id: 0 } } ]} }
] )
Résultat :
{ "name" :"Fluffy" }{ "name" :"Scratch" }{ "name" :"Meow" }{ "name" :"Wag" }{ "name" :"Bark" }{ " name" :"Fluffy" }
Supprimer les doublons
Vous pouvez utiliser le $group
étape pour éliminer les doublons redondants du résultat.
Par exemple, la requête précédente a renvoyé deux animaux appelés Fluffy. Nous pouvons ajouter un $group
étape à cette requête pour éliminer le doublon redondant, de sorte qu'un seul Fluffy est renvoyé.
db.cats.aggregate( [
{ $project: { name: 1, _id: 0 } },
{ $unionWith: { coll: "dogs", pipeline: [ { $project: { name: 1, _id: 0 } } ]} },
{ $group: { _id: "$name" } }
] )
Résultat :
{ "_id" :"Meow" }{ "_id" :"Bark" }{ "_id" :"Scratch" }{ "_id" :"Wag" }{ "_id" :"Fluffy" }Cette fois, un seul Fluffy est retourné.
Colonnes non correspondantes
L'un des avantages de
$unionWith
de MongoDB a surUNION ALL
de SQL est qu'il peut être utilisé avec des colonnes non correspondantes.L'
UNION
SQL clause requiert que :
- Les deux requêtes renvoient le même nombre de colonnes
- Les colonnes dans le même ordre
- Les colonnes correspondantes doivent être d'un type de données compatible
Le MongoDB $unionWith
stage n'impose pas ces limitations.
Par conséquent, nous pourrions utiliser $unionWith
pour faire quelque chose comme ça :
db.cats.aggregate( [
{ $set: { _id: "$_id" } },
{ $unionWith: { coll: "employees", pipeline: [ { $set: { _id: "$_id" } } ] } },
{ $sort: { type: 1, salary: -1 } }
] )
Résultat :
{ "_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" :"Chat", "poids" :5 }{ "_id" :2, "nom" :"Scratch", "type" :"Chat", "poids" :3 }{ "_id" :3, "nom" :"Miaou", "type" :"Chat", "poids" :7 }
Dans ce cas, nous avons rejoint les cats
collecte auprès des employees
le recueil. Les employees
la collection n'avait pas les mêmes champs que les cats
collection, mais c'est très bien - ça a quand même fonctionné.