Definición
$unionWithCambiado en la versión 8.0.
Combina dos agregaciones en un único conjunto de resultados.
$unionWithproduce el conjunto combinado de resultados (incluidos los duplicados) a la siguiente etapa.El orden en el que se generan los documentos del conjunto de resultados combinado no está especificado.
Sintaxis
La etapa $unionWith tiene la siguiente sintaxis:
{ $unionWith: { coll: "<collection>", pipeline: [ <stage1>, ... ] } }
Para incluir todos los documentos de la colección especificada sin ningún procesamiento, puede utilizar la forma simplificada:
{ $unionWith: "<collection>" } // Include all documents from the specified collection
La etapa $unionWith procesa un documento con los siguientes campos:
Campo | Necesidad | Descripción |
|---|---|---|
Requerido si se omite | La colección o vista cuyos resultados de canalización desea incluir en el conjunto de resultados. Si omite el campo | |
Requerido si se omite | Una canalización de agregación para aplicar a los documentos de entrada.
La canalización no puede incluir las etapas |
La operación $unionWith correspondería a la siguiente instrucción SQL:
SELECT * FROM Collection1 WHERE ... UNION ALL SELECT * FROM Collection2 WHERE ...
Considerations
Resultados duplicados
Los resultados combinados de la etapa anterior y la etapa $unionWith pueden incluir duplicados.
Por ejemplo, crea una colección suppliers y una colección warehouses:
db.suppliers.insertMany([ { _id: 1, supplier: "Aardvark and Sons", state: "Texas" }, { _id: 2, supplier: "Bears Run Amok.", state: "Colorado"}, { _id: 3, supplier: "Squid Mark Inc. ", state: "Rhode Island" }, ])
db.warehouses.insertMany([ { _id: 1, warehouse: "A", region: "West", state: "California" }, { _id: 2, warehouse: "B", region: "Central", state: "Colorado"}, { _id: 3, warehouse: "C", region: "East", state: "Florida" }, ])
La siguiente agregación combina los resultados de la proyección del campo state de las colecciones suppliers y warehouse.
db.suppliers.aggregate([ { $project: { state: 1, _id: 0 } }, { $unionWith: { coll: "warehouses", pipeline: [ { $project: { state: 1, _id: 0 } } ]} } ])
El conjunto de resultados contiene duplicados:
{ "state" : "Texas" } { "state" : "Colorado" } { "state" : "Rhode Island" } { "state" : "California" } { "state" : "Colorado" } { "state" : "Florida" }
Para remover los duplicados, se puede incluir una etapa $group para agrupar por el campo state:
db.suppliers.aggregate([ { $project: { state: 1, _id: 0 } }, { $unionWith: { coll: "warehouses", pipeline: [ { $project: { state: 1, _id: 0 } } ]} }, { $group: { _id: "$state" } } ])
El conjunto de resultados ya no contiene duplicados:
{ "_id" : "California" } { "_id" : "Texas" } { "_id" : "Florida" } { "_id" : "Colorado" } { "_id" : "Rhode Island" }
Intercalación
Si el db.collection.aggregate() incluye un documento collation, la operación utiliza esa intercalación y omite cualquier otra intercalación.
Si el db.collection.aggregate() no incluye un documento collation, el método db.collection.aggregate() utiliza la intercalación para la colección/vista de nivel superior en la que se ejecuta el db.collection.aggregate():
Si la coll $unionWith es una colección, su intercalación se ignora.
Si la coll $unionWith es una vista, su intercalación debe coincidir con la de la colección/vista de nivel superior. De lo contrario, la operación generará un error.
Soporte para MongoDB Search
A partir de MongoDB 6.0, puede especificar la etapa de búsqueda de MongoDB $search o $searchMeta en la canalización $unionWith para buscar colecciones en el clúster Atlas. La etapa $search o $searchMeta debe ser la primera etapa dentro de la canalización $unionWith.
[{ "$unionWith": { "coll": <collection-name>, "pipeline": [{ "$search": { "<operator>": { <operator-specification> } }, ... }] } }]
[{ "$unionWith": { "coll": <collection-name>, "pipeline": [{ "$searchMeta": { "<collector>": { <collector-specification> } }, ... }] } }]
Para ver un ejemplo de $unionWith con $search, consulte el tutorial de búsqueda de MongoDB Ejecutar una consulta de búsqueda de MongoDB $search usando $unionWith.
Restricciones
Restricciones | Descripción |
|---|---|
Una canalización de agregación no puede usar | |
La canalización $unionWith no puede incluir la etapa | |
La canalización $unionWith no puede incluir la etapa |
Ejemplos
Crear informes de ventas a partir de la Unión de colecciones de datos anuales
Los siguientes ejemplos utilizan la etapa $unionWith para combinar datos y devolver resultados de varias colecciones. En estos ejemplos, cada colección contiene datos de ventas de un año.
Poblar datos de muestra
Crea una colección
sales_2017con los siguientes documentos:db.sales_2017.insertMany( [ { store: "General Store", item: "Chocolates", quantity: 150 }, { store: "ShopMart", item: "Chocolates", quantity: 50 }, { store: "General Store", item: "Cookies", quantity: 100 }, { store: "ShopMart", item: "Cookies", quantity: 120 }, { store: "General Store", item: "Pie", quantity: 10 }, { store: "ShopMart", item: "Pie", quantity: 5 } ] ) Crea una colección
sales_2018con los siguientes documentos:db.sales_2018.insertMany( [ { store: "General Store", item: "Cheese", quantity: 30 }, { store: "ShopMart", item: "Cheese", quantity: 50 }, { store: "General Store", item: "Chocolates", quantity: 125 }, { store: "ShopMart", item: "Chocolates", quantity: 150 }, { store: "General Store", item: "Cookies", quantity: 200 }, { store: "ShopMart", item: "Cookies", quantity: 100 }, { store: "ShopMart", item: "Nuts", quantity: 100 }, { store: "General Store", item: "Pie", quantity: 30 }, { store: "ShopMart", item: "Pie", quantity: 25 } ] ) Crea una colección
sales_2019con los siguientes documentos:db.sales_2019.insertMany( [ { store: "General Store", item: "Cheese", quantity: 50 }, { store: "ShopMart", item: "Cheese", quantity: 20 }, { store: "General Store", item: "Chocolates", quantity: 125 }, { store: "ShopMart", item: "Chocolates", quantity: 150 }, { store: "General Store", item: "Cookies", quantity: 200 }, { store: "ShopMart", item: "Cookies", quantity: 100 }, { store: "General Store", item: "Nuts", quantity: 80 }, { store: "ShopMart", item: "Nuts", quantity: 30 }, { store: "General Store", item: "Pie", quantity: 50 }, { store: "ShopMart", item: "Pie", quantity: 75 } ] ) Crea una colección
sales_2020con los siguientes documentos:db.sales_2020.insertMany( [ { store: "General Store", item: "Cheese", quantity: 100, }, { store: "ShopMart", item: "Cheese", quantity: 100}, { store: "General Store", item: "Chocolates", quantity: 200 }, { store: "ShopMart", item: "Chocolates", quantity: 300 }, { store: "General Store", item: "Cookies", quantity: 500 }, { store: "ShopMart", item: "Cookies", quantity: 400 }, { store: "General Store", item: "Nuts", quantity: 100 }, { store: "ShopMart", item: "Nuts", quantity: 200 }, { store: "General Store", item: "Pie", quantity: 100 }, { store: "ShopMart", item: "Pie", quantity: 100 } ] )
Informe 1: todas las ventas por año, almacenes y artículos
La siguiente agregación crea un informe anual de ventas que enumera todas las ventas por trimestre y por almacenes. El pipeline utiliza $unionWith para combinar documentos de las cuatro colecciones:
db.sales_2017.aggregate( [ { $set: { _id: "2017" } }, { $unionWith: { coll: "sales_2018", pipeline: [ { $set: { _id: "2018" } } ] } }, { $unionWith: { coll: "sales_2019", pipeline: [ { $set: { _id: "2019" } } ] } }, { $unionWith: { coll: "sales_2020", pipeline: [ { $set: { _id: "2020" } } ] } }, { $sort: { _id: 1, store: 1, item: 1 } } ] )
En concreto, la pipeline de agregación utiliza:
Una
$setetapa para actualizar el campo_idpara que contenga el año.Una secuencia de
$unionWithetapas para combinar todos los documentos de las cuatro colecciones, cada una utilizando también la etapa$seten sus documentos.Una
$sortetapa para ordenar por el_id(el año), elstoreyitem.
Salida del pipeline:
{ "_id" : "2017", "store" : "General Store", "item" : "Chocolates", "quantity" : 150 } { "_id" : "2017", "store" : "General Store", "item" : "Cookies", "quantity" : 100 } { "_id" : "2017", "store" : "General Store", "item" : "Pie", "quantity" : 10 } { "_id" : "2017", "store" : "ShopMart", "item" : "Chocolates", "quantity" : 50 } { "_id" : "2017", "store" : "ShopMart", "item" : "Cookies", "quantity" : 120 } { "_id" : "2017", "store" : "ShopMart", "item" : "Pie", "quantity" : 5 } { "_id" : "2018", "store" : "General Store", "item" : "Cheese", "quantity" : 30 } { "_id" : "2018", "store" : "General Store", "item" : "Chocolates", "quantity" : 125 } { "_id" : "2018", "store" : "General Store", "item" : "Cookies", "quantity" : 200 } { "_id" : "2018", "store" : "General Store", "item" : "Pie", "quantity" : 30 } { "_id" : "2018", "store" : "ShopMart", "item" : "Cheese", "quantity" : 50 } { "_id" : "2018", "store" : "ShopMart", "item" : "Chocolates", "quantity" : 150 } { "_id" : "2018", "store" : "ShopMart", "item" : "Cookies", "quantity" : 100 } { "_id" : "2018", "store" : "ShopMart", "item" : "Nuts", "quantity" : 100 } { "_id" : "2018", "store" : "ShopMart", "item" : "Pie", "quantity" : 25 } { "_id" : "2019", "store" : "General Store", "item" : "Cheese", "quantity" : 50 } { "_id" : "2019", "store" : "General Store", "item" : "Chocolates", "quantity" : 125 } { "_id" : "2019", "store" : "General Store", "item" : "Cookies", "quantity" : 200 } { "_id" : "2019", "store" : "General Store", "item" : "Nuts", "quantity" : 80 } { "_id" : "2019", "store" : "General Store", "item" : "Pie", "quantity" : 50 } { "_id" : "2019", "store" : "ShopMart", "item" : "Cheese", "quantity" : 20 } { "_id" : "2019", "store" : "ShopMart", "item" : "Chocolates", "quantity" : 150 } { "_id" : "2019", "store" : "ShopMart", "item" : "Cookies", "quantity" : 100 } { "_id" : "2019", "store" : "ShopMart", "item" : "Nuts", "quantity" : 30 } { "_id" : "2019", "store" : "ShopMart", "item" : "Pie", "quantity" : 75 } { "_id" : "2020", "store" : "General Store", "item" : "Cheese", "quantity" : 100 } { "_id" : "2020", "store" : "General Store", "item" : "Chocolates", "quantity" : 200 } { "_id" : "2020", "store" : "General Store", "item" : "Cookies", "quantity" : 500 } { "_id" : "2020", "store" : "General Store", "item" : "Nuts", "quantity" : 100 } { "_id" : "2020", "store" : "General Store", "item" : "Pie", "quantity" : 100 } { "_id" : "2020", "store" : "ShopMart", "item" : "Cheese", "quantity" : 100 } { "_id" : "2020", "store" : "ShopMart", "item" : "Chocolates", "quantity" : 300 } { "_id" : "2020", "store" : "ShopMart", "item" : "Cookies", "quantity" : 400 } { "_id" : "2020", "store" : "ShopMart", "item" : "Nuts", "quantity" : 200 } { "_id" : "2020", "store" : "ShopMart", "item" : "Pie", "quantity" : 100 }
Informe 2: ventas totales por artículos
La siguiente agregación crea un informe de ventas que muestra la cantidad vendida por artículo. El proceso utiliza $unionWith para combinar documentos de los cuatro años:
db.sales_2017.aggregate( [ { $unionWith: "sales_2018" }, { $unionWith: "sales_2019" }, { $unionWith: "sales_2020" }, { $group: { _id: "$item", total: { $sum: "$quantity" } } }, { $sort: { total: -1 } } ] )
La secuencia de etapas
$unionWithrecupera documentos de las colecciones especificadas en la canalización:La
$sortetapa ordena los documentos portotalde forma descendente.
Salida del pipeline:
{ "_id" : "Cookies", "total" : 1720 } { "_id" : "Chocolates", "total" : 1250 } { "_id" : "Nuts", "total" : 510 } { "_id" : "Pie", "total" : 395 } { "_id" : "Cheese", "total" : 350 }
Crea una unión con documentos específicos
Puedes utilizar $unionWith para realizar una unión con los documentos que especifiques en el campo pipeline. Cuando especificas una etapa $documents en el campo pipeline, realizas una unión con documentos que no están almacenados en una colección separada.
Cree una colección cakeFlavors:
db.cakeFlavors.insertMany( [ { _id: 1, flavor: "chocolate" }, { _id: 2, flavor: "strawberry" }, { _id: 3, flavor: "cherry" } ] )
La siguiente operación $unionWith realiza una unión con los documentos especificados en el campo pipeline $documents:
db.cakeFlavors.aggregate( [ { $unionWith: { pipeline: [ { $documents: [ { _id: 4, flavor: "orange" }, { _id: 5, flavor: "vanilla", price: 20 } ] } ] } } ] )
Salida:
[ { _id: 1, flavor: 'chocolate' }, { _id: 2, flavor: 'strawberry' }, { _id: 3, flavor: 'cherry' }, { _id: 4, flavor: 'orange' }, { _id: 5, flavor: 'vanilla', price: 20 } ]
Namespaces en subcanalizaciones
A partir de MongoDB 8.0, namespaces en subpipelines dentro de $lookup y $unionWith se validan para asegurar el uso correcto de los campos from y coll:
Para
$lookup, omite el campofromsi utilizas una subpipeline con una etapa que no requiera una colección especificada. Por ejemplo, una etapa$documents.De manera similar, para
$unionWith, omite el campocoll.
Comportamiento sin cambio:
Para un
$lookupque comienza con una etapa para una colección, por ejemplo, una sub-etapa$matcho$collStats, debes incluir el campofromy especificar la colección.De manera similar, para
$unionWith, incluye el campocolly especifica la colección.
El siguiente escenario muestra un ejemplo.
Cree una colección cakeFlavors:
db.cakeFlavors.insertMany( [ { _id: 1, flavor: "chocolate" }, { _id: 2, flavor: "strawberry" }, { _id: 3, flavor: "cherry" } ] )
A partir de MongoDB 8.0, el siguiente ejemplo devuelve un error porque contiene un campo coll no válido:
db.cakeFlavors.aggregate( [ { $unionWith: { coll: "cakeFlavors", pipeline: [ { $documents: [] } ] } } ] )
En las versiones de MongoDB anteriores a 8.0, se ejecuta el ejemplo anterior.
Para un ejemplo con un campo coll válido, consulta Duplicate Results.
Los ejemplos de C# en esta página utilizan la base de datos sample_mflix de los conjuntos de datos de muestra de Atlas. Para aprender a crear un clúster gratuito de MongoDB Atlas y cargar los conjuntos de datos de muestra, consulta Primeros pasos en la documentación del controlador de MongoDB .NET/C#.
La siguiente clase Movie modela los documentos en la colección sample_mflix.movies:
[] public class Movie { [] public ObjectId Id { get; set; } [] public string Title { get; set; } = null!; [] public int? Year { get; set; } [] public int? Runtime { get; set; } [] public string? Rated { get; set; } [] public int Metacritic { get; set; } [] public string? Plot { get; set; } [] public string? Type { get; set; } [] public string[]? Cast { get; set; } [] public string[]? Directors { get; set; } [] public string[]? Writers { get; set; } [] public ImdbData? Imdb { get; set; } }
Para usar el controlador MongoDB.NET/C# para agregar una etapa $unionWith a una canalización de agregación, llame al método UnionWith() en un objeto PipelineDefinition.
El siguiente ejemplo crea una etapa de la pipeline que combina películas con una puntuación Metacritic de 100 de la colección sample_mflix.movies con películas que cumplen los mismos criterios:
var pipeline = new EmptyPipelineDefinition<Movie>() .Match(Builders<Movie>.Filter.Eq(m => m.Metacritic, 100)) .UnionWith( withCollection: _movies, withPipeline: new EmptyPipelineDefinition<Movie>() .Match(Builders<Movie>.Filter.Eq(m => m.Metacritic, 100)));
{ "metacritic" : 100, "title" : "Best Kept Secret" } { "metacritic" : 100, "title" : "Best Kept Secret" } { "metacritic" : 100, "title" : "Boyhood" } { "metacritic" : 100, "title" : "Boyhood" } { "metacritic" : 100, "title" : "Fanny and Alexander" } { "metacritic" : 100, "title" : "Fanny and Alexander" } { "metacritic" : 100, "title" : "Lawrence of Arabia" } { "metacritic" : 100, "title" : "Lawrence of Arabia" } { "metacritic" : 100, "title" : "The Conformist" } { "metacritic" : 100, "title" : "The Conformist" } { "metacritic" : 100, "title" : "The Godfather" } { "metacritic" : 100, "title" : "The Godfather" } { "metacritic" : 100, "title" : "The Leopard" } { "metacritic" : 100, "title" : "The Leopard" } { "metacritic" : 100, "title" : "The Wizard of Oz" } { "metacritic" : 100, "title" : "The Wizard of Oz" }
Los ejemplos de Node.js de esta página utilizan la base de datos sample_mflix de los conjuntos de datos de ejemplo de Atlas. Para aprender a crear un clúster gratuito de MongoDB Atlas y cargar los conjuntos de datos de ejemplo, consulte la sección «Primeros pasos» en la documentación del controlador de MongoDB para Node.js.
Para utilizar el controlador de MongoDB Node.js para agregar una etapa de $unionWith a una canalización de agregación, utilice el Operador $unionWith en un objeto de canalización.
El siguiente ejemplo crea una etapa de pipeline que combina los documentos entrantes de la colección sample_mflix.movies con los documentos movie de la colección sample_mflix.movies. A continuación, el ejemplo ejecuta la canalización de agregación:
const db = client.db("sample_mflix"); const collection = db.collection("movies"); const pipeline = [{ $unionWith: { coll: "Movies" } }]; const cursor = collection.aggregate(pipeline); return cursor;