Правенето на обединения в 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(). Почти всичко, което искате.