MongoDB
 sql >> Base de données >  >> NoSQL >> MongoDB

$unionWith - L'équivalent de UNION ALL pour MongoDB

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 sur UNION 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é.