Faire des unions dans MongoDB de manière "SQL UNION" est possible en utilisant des agrégations avec des recherches, dans une seule requête.
Quelque chose comme ça :
db.getCollection("AnyCollectionThatContainsAtLeastOneDocument").aggregate(
[
{ $limit: 1 }, // Reduce the result set to a single document.
{ $project: { _id: 1 } }, // Strip all fields except the Id.
{ $project: { _id: 0 } }, // Strip the id. The document is now empty.
// Lookup all collections to union together.
{ $lookup: { from: 'collectionToUnion1', pipeline: [...], as: 'Collection1' } },
{ $lookup: { from: 'collectionToUnion2', pipeline: [...], as: 'Collection2' } },
{ $lookup: { from: 'collectionToUnion3', pipeline: [...], as: 'Collection3' } },
// Merge the collections together.
{
$project:
{
Union: { $concatArrays: ["$Collection1", "$Collection2", "$Collection3"] }
}
},
{ $unwind: "$Union" }, // Unwind the union collection into a result set.
{ $replaceRoot: { newRoot: "$Union" } } // Replace the root to cleanup the resulting documents.
]);
Voici l'explication de son fonctionnement :
-
Instancier un
aggregate
sur tout collection de votre base de données contenant au moins un document. Si vous ne pouvez pas garantir qu'aucune collection de votre base de données ne sera vide, vous pouvez contourner ce problème en créant dans votre base de données une sorte de collection 'factice' contenant un seul document vide qui sera là spécifiquement pour faire des requêtes d'union. -
Faites en sorte que la première étape de votre pipeline soit
{ $limit: 1 }
. Cela supprimera tous les documents de la collection sauf le premier. -
Supprimez tous les champs du document restant en utilisant
$project
étapes :{ $project: { _id: 1 } }, { $project: { _id: 0 } }
-
Votre agrégat contient maintenant un seul document vide. Il est temps d'ajouter des recherches pour chaque collection que vous souhaitez regrouper. Vous pouvez utiliser le
pipeline
champ pour effectuer un filtrage spécifique, ou laissezlocalField
etforeignField
comme null pour correspondre à toute la collection.{ $lookup: { from: 'collectionToUnion1', pipeline: [...], as: 'Collection1' } }, { $lookup: { from: 'collectionToUnion2', pipeline: [...], as: 'Collection2' } }, { $lookup: { from: 'collectionToUnion3', pipeline: [...], as: 'Collection3' } }
-
Vous avez maintenant un agrégat contenant un seul document qui contient 3 tableaux comme celui-ci :
{ Collection1: [...], Collection2: [...], Collection3: [...] }
Vous pouvez ensuite les fusionner en un seul tableau à l'aide d'un
$project
étape avec le$concatArrays
opérateur d'agrégation :{ "$project" : { "Union" : { $concatArrays: ["$Collection1", "$Collection2", "$Collection3"] } } }
-
Vous avez maintenant un agrégat contenant un seul document, dans lequel se trouve un tableau qui contient votre union de collections. Il ne reste plus qu'à ajouter un
$unwind
et un$replaceRoot
étape pour diviser votre tableau en documents distincts :{ $unwind: "$Union" }, { $replaceRoot: { newRoot: "$Union" } }
-
Voilà. Vous savez que vous avez un jeu de résultats contenant les collections que vous vouliez réunir. Vous pouvez ensuite ajouter plus d'étapes pour le filtrer davantage, le trier, appliquer skip() et limit(). À peu près tout ce que vous voulez.