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
aggregate
de 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
$project
etapas:{ $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
pipeline
campo para hacer un filtrado específico, o dejarlocalField
yforeignField
como 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
$project
escenario junto con$concatArrays
operador 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
$unwind
y un$replaceRoot
etapa 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.