Правенето на обединения в MongoDB по начин на „SQL UNION“ е възможно с помощта на агрегации заедно с търсения в една заявка.
Нещо като това:
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.
]);
Ето обяснението как работи:
-
Създайте
aggregateот всякакви колекция от вашата база данни, която има поне един документ в нея. Ако не можете да гарантирате, че никоя колекция от вашата база данни няма да е празна, можете да заобиколите този проблем, като създадете във вашата база данни някаква „фиктивна“ колекция, съдържаща един празен документ в нея, който ще бъде там специално за извършване на заявки за съюз. -
Направете първия етап от вашия конвейер да бъде
{ $limit: 1 }. Това ще премахне всички документи от колекцията с изключение на първия. -
Изчистете всички полета на оставащия документ с помощта на
$projectетапи:{ $project: { _id: 1 } }, { $project: { _id: 0 } } -
Вашият агрегат вече съдържа един-единствен празен документ. Време е да добавите справки за всяка колекция, която искате да обедините. Можете да използвате
pipelineполе, за да направите някакво конкретно филтриране, или оставетеlocalFieldиforeignFieldкато нула, за да съответства на цялата колекция.{ $lookup: { from: 'collectionToUnion1', pipeline: [...], as: 'Collection1' } }, { $lookup: { from: 'collectionToUnion2', pipeline: [...], as: 'Collection2' } }, { $lookup: { from: 'collectionToUnion3', pipeline: [...], as: 'Collection3' } } -
Вече имате агрегат, съдържащ единичен документ, който съдържа 3 масива като този:
{ Collection1: [...], Collection2: [...], Collection3: [...] }След това можете да ги обедините заедно в един масив с помощта на
$projectетап заедно с$concatArraysоператор на агрегиране:{ "$project" : { "Union" : { $concatArrays: ["$Collection1", "$Collection2", "$Collection3"] } } } -
Вече имате агрегат, съдържащ един-единствен документ, в който е разположен масив, който съдържа вашия съюз от колекции. Това, което остава да се направи, е да добавите
$unwindи$replaceRootетап, за да разделите вашия масив на отделни документи:{ $unwind: "$Union" }, { $replaceRoot: { newRoot: "$Union" } } -
Voilà. Знаете, че имате набор от резултати, съдържащ колекциите, които искате да обедините заедно. След това можете да добавите още етапи, за да го филтрирате допълнително, да го сортирате, да приложите skip() и limit(). Почти всичко, което искате.