Es posible realizar uniones en MongoDB al estilo 'SQL UNION' utilizando agregaciones junto con búsquedas, en una sola consulta.
Algo como esto:
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.
]);
Aquí está la explicación de cómo funciona:
-
Crear una instancia de un
aggregatede cualquiera colección de su base de datos que tiene al menos un documento en ella. Si no puede garantizar que ninguna colección de su base de datos esté vacía, puede solucionar este problema creando en su base de datos algún tipo de colección 'ficticia' que contenga un único documento vacío que estará allí específicamente para realizar consultas de unión. -
Haga que la primera etapa de su canalización sea
{ $limit: 1 }. Esto eliminará todos los documentos de la colección excepto el primero. -
Elimina todos los campos del documento restante usando
$projectetapas:{ $project: { _id: 1 } }, { $project: { _id: 0 } } -
Su agregado ahora contiene un único documento vacío. Es hora de agregar búsquedas para cada colección que desee unir. Puede usar la
pipelinecampo para hacer un filtrado específico, o dejarlocalFieldyforeignFieldcomo nulo para que coincida con toda la colección.{ $lookup: { from: 'collectionToUnion1', pipeline: [...], as: 'Collection1' } }, { $lookup: { from: 'collectionToUnion2', pipeline: [...], as: 'Collection2' } }, { $lookup: { from: 'collectionToUnion3', pipeline: [...], as: 'Collection3' } } -
Ahora tiene un agregado que contiene un solo documento que contiene 3 matrices como esta:
{ Collection1: [...], Collection2: [...], Collection3: [...] }Luego puede fusionarlos en una sola matriz usando un
$projectescenario junto con$concatArraysoperador de agregación:{ "$project" : { "Union" : { $concatArrays: ["$Collection1", "$Collection2", "$Collection3"] } } } -
Ahora tiene un agregado que contiene un solo documento, en el que se encuentra una matriz que contiene su unión de colecciones. Lo que queda por hacer es agregar un
$unwindy un$replaceRootetapa para dividir su matriz en documentos separados:{ $unwind: "$Union" }, { $replaceRoot: { newRoot: "$Union" } } -
Voila. Sabe que tiene un conjunto de resultados que contiene las colecciones que quería unir. Luego puede agregar más etapas para filtrarlo aún más, ordenarlo, aplicar skip() y limit(). Prácticamente todo lo que quieras.