At lave fagforeninger i MongoDB på en "SQL UNION"-måde er muligt ved at bruge aggregeringer sammen med opslag i en enkelt forespørgsel.
Noget som dette:
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.
]);
Her er forklaringen på, hvordan det virker:
-
Instantiér et
aggregate
ud af enhver samling af din database, der har mindst ét dokument i sig. Hvis du ikke kan garantere, at en samling af din database ikke vil være tom, kan du omgå dette problem ved at oprette en slags 'dummy'-samling i din database, der indeholder et enkelt tomt dokument, der vil være der specifikt til at lave fagforeningsforespørgsler. -
Gør den første fase af din pipeline til at være
{ $limit: 1 }
. Dette fjerner alle dokumenter fra samlingen undtagen det første. -
Fjern alle felterne i det resterende dokument ved at bruge
$project
stadier:{ $project: { _id: 1 } }, { $project: { _id: 0 } }
-
Dit aggregat indeholder nu et enkelt, tomt dokument. Det er tid til at tilføje opslag for hver samling, du vil forene sammen. Du kan bruge
pipeline
felt for at udføre en specifik filtrering, eller forladlocalField
ogforeignField
som null for at matche hele samlingen.{ $lookup: { from: 'collectionToUnion1', pipeline: [...], as: 'Collection1' } }, { $lookup: { from: 'collectionToUnion2', pipeline: [...], as: 'Collection2' } }, { $lookup: { from: 'collectionToUnion3', pipeline: [...], as: 'Collection3' } }
-
Du har nu et aggregat, der indeholder et enkelt dokument, der indeholder 3 arrays som dette:
{ Collection1: [...], Collection2: [...], Collection3: [...] }
Du kan derefter flette dem sammen til et enkelt array ved hjælp af et
$project
fase sammen med$concatArrays
aggregeringsoperatør:{ "$project" : { "Union" : { $concatArrays: ["$Collection1", "$Collection2", "$Collection3"] } } }
-
Du har nu et aggregat, der indeholder et enkelt dokument, hvori der er placeret et array, der indeholder din forening af samlinger. Det, der mangler at blive gjort, er at tilføje en
$unwind
og en$replaceRoot
trin for at opdele dit array i separate dokumenter:{ $unwind: "$Union" }, { $replaceRoot: { newRoot: "$Union" } }
-
Voilà. Du ved, at du har et resultatsæt, der indeholder de samlinger, du ønskede at forene sammen. Du kan derefter tilføje flere stadier for at filtrere det yderligere, sortere det, anvende skip() og limit(). Stort set alt, hvad du ønsker.