Docs Menu
Docs Home
/ /
Etapas de la pipeline de agregación

$lookup (agregación)

$lookup

Modificado en la versión 5.0.

Realiza una unión externa izquierda a una colección no fragmentada de la misma base de datos para filtrar los documentos de la colección unida para su procesamiento. A cada documento de entrada, la $lookup etapa añade un nuevo campo de matriz cuyos elementos son los documentos coincidentes de la colección unida. La $lookup etapa pasa estos documentos reestructurados a la siguiente etapa.

Puedes usar $lookup para implementaciones alojadas en los siguientes entornos:

  • MongoDB Atlas: El servicio totalmente gestionado para implementaciones de MongoDB en la nube

  • MongoDB Enterprise: La versión basada en suscripción y autogestionada de MongoDB

  • MongoDB Community: La versión de MongoDB con código fuente disponible, de uso gratuito y autogestionada.

La etapa tiene las siguientes $lookup sintaxis:

Para realizar una coincidencia de igualdad entre un campo de los documentos de entrada con un campo de los documentos de la colección "unida", la etapa tiene esta $lookup sintaxis:

{
$lookup:
{
from: <collection to join>,
localField: <field from the input documents>,
foreignField: <field from the documents of the "from" collection>,
as: <output array field>
}
}

El toma un documento con estos $lookup campos:

Campo
Descripción

Especifica la colección en la misma base de datos con la que se realizará la unión. La from colección no se puede fragmentar. Para obtener más información, consulte Restricciones de colecciones fragmentadas.

Especifica el campo de la entrada de documentos para la etapa $lookup. $lookup realiza una coincidencia exacta en el localField con el foreignField de los documentos de la colección from. Si un documento de entrada no contiene el localField, el $lookup trata el campo como si tuviera un valor de null para fines de coincidencia.

Especifica el campo de los documentos de la from colección. realiza una coincidencia de igualdad entre$lookup el foreignField y el localField de los documentos de entrada. Si un documento de la from colección no contiene foreignField el, trata el valor $lookup como null para la coincidencia.

Especifica el nombre del nuevo campo de arreglo que se añadirá a los documentos de entrada. El nuevo campo de arreglo contiene los documentos coincidentes de la colección from. Si el nombre especificado ya existe en el documento de entrada, el campo existente se sobrescribe.

La operación corresponde a esta instrucción pseudo-SQL:

SELECT *, (
SELECT ARRAY_AGG(*)
FROM <collection to join>
WHERE <foreignField> = <collection.localField>
) AS <output array field>
FROM collection;

Nota

Las instrucciones SQL de esta página se incluyen para compararlas con la sintaxis de la pipeline de agregación de MongoDB. Las instrucciones SQL no son ejecutables.

Para ejemplos de MongoDB, consulte estas páginas:

MongoDB admite:

  • Ejecutar una canalización en una colección unida.

  • Múltiples condiciones de combinación.

  • Subconsultas correlacionadas y no correlacionadas.

En MongoDB, una subconsulta correlacionada es una canalización en una $lookup etapa que hace referencia a campos de documento de una colección unida. Una subconsulta no correlacionada no hace referencia a campos unidos.

Nota

A partir de MongoDB 5.0, para un subquery no correlacionado en una etapa de la pipeline de $lookup que contenga una etapa $sample, el operador $sampleRate o el operador $rand, el subquery siempre se ejecuta nuevamente si se repite. Anteriormente, según el tamaño del resultado del subquery, se almacenaba en caché o el subquery se ejecutaba nuevamente.

Las sub-query correlacionadas de MongoDB son comparables a las sub-query correlacionadas de SQL, donde la query interna hace referencia a los valores externos de la query. Una sub-query no correlacionada de SQL no hace referencia a valores de la query externa.

MongoDB 5.0 también soporta a los subquery correlacionados concisos.

Para realizar los subquery correlacionados y no correlacionados con dos colecciones, y realizar otras condiciones de unión además de una única coincidencia exacta, utiliza esta sintaxis de $lookup:

{
$lookup:
{
from: <joined collection>,
let: { <var_1>: <expression>, …, <var_n>: <expression> },
pipeline: [ <pipeline to run on joined collection> ],
as: <output array field>
}
}

La etapa acepta un documento con estos $lookup campos:

Campo
Descripción

Especifica la colección en la misma base de datos para realizar la operación de unión. La colección unida no se puede fragmentar (consulte Restricciones de colecciones fragmentadas).

Opcional. Especifica las variables que se usarán en las etapas de la canalización. Utilice las expresiones de variable para acceder a los campos de los documentos de la colección unida que se utilizan como entrada pipeline en.

Para referenciar variables en las etapas de un pipeline, utiliza la sintaxis "$$<variable>".

Se puede acceder a las variables let por las etapas de la pipeline, incluidas las etapas adicionales$lookup anidadas en el pipeline.

  • Una etapa $match requiere el uso de un operador $expr para acceder a las variables. El operador $expr permite el uso de expresiones de agregación dentro de la sintaxis de $match.

    Los operadores de comparación $eq, $lt, $lte, $gt y $gte colocados en un operador $expr pueden utilizar un índice en la colección from referenciada en una etapa $lookup. Limitaciones:

    • Los índices solo pueden utilizarse para comparaciones entre campos y constantes, por lo que el operando let debe resolverse en una constante.

      Por ejemplo, una comparación entre $a y un valor constante puede utilizar un índice, pero una comparación entre $a y $b no puede.

    • Los índices no se utilizan para comparaciones donde el operando let se resuelve en un valor vacío o faltante.

    • Los índices multiclave no se utilizan.

  • Otras etapas (no$match) de la pipeline no requieren un operador $exprpara acceder a las variables.

Especifica el valor pipeline que se ejecutará en la colección unida. El valor pipeline determina los documentos resultantes de la colección unida. Para devolver todos los documentos, especifique un valor pipeline [] vacío.

El pipeline no puede incluir la etapa $out $merge ni la etapa.

pipeline no puede acceder directamente a los campos de documento combinados. En su lugar, define variables para los campos de documentos combinados usando la opción let y luego referencia las variables en las etapas pipeline.

Para referenciar variables en las etapas de un pipeline, utiliza la sintaxis "$$<variable>".

Se puede acceder a las variables let por las etapas de la pipeline, incluidas las etapas adicionales$lookup anidadas en el pipeline.

  • Una etapa $match requiere el uso de un operador $expr para acceder a las variables. El operador $expr permite el uso de expresiones de agregación dentro de la sintaxis de $match.

    Los operadores de comparación $eq, $lt, $lte, $gt y $gte colocados en un operador $expr pueden utilizar un índice en la colección from referenciada en una etapa $lookup. Limitaciones:

    • Los índices solo pueden utilizarse para comparaciones entre campos y constantes, por lo que el operando let debe resolverse en una constante.

      Por ejemplo, una comparación entre $a y un valor constante puede utilizar un índice, pero una comparación entre $a y $b no puede.

    • Los índices no se utilizan para comparaciones donde el operando let se resuelve en un valor vacío o faltante.

    • Los índices multiclave no se utilizan.

  • Otras etapas (no$match) de la pipeline no requieren un operador $exprpara acceder a las variables.

Especifica el nombre del nuevo campo de matriz que se añadirá a los documentos unidos. Este campo contiene los documentos coincidentes de la colección unida. Si el nombre especificado ya existe en el documento unido, se sobrescribe el campo existente.

La operación corresponde a esta instrucción pseudo-SQL:

SELECT *, <output array field>
FROM collection
WHERE <output array field> IN (
SELECT <documents as determined from the pipeline>
FROM <collection to join>
WHERE <pipeline>
);

Vea los siguientes ejemplos:

Nuevo en la versión 5.0.

A partir de MongoDB,5.0 se puede usar una sintaxis concisa para una subconsulta correlacionada. Las subconsultas correlacionadas hacen referencia a campos de documento de una colección externa unida y de la colección local donde aggregate() se ejecutó el método.

La siguiente nueva sintaxis concisa elimina el requisito de una coincidencia exacta en los campos foráneo y local dentro de un operador $expr:

{
$lookup:
{
from: <foreign collection>,
localField: <field from local collection's documents>,
foreignField: <field from foreign collection's documents>,
let: { <var_1>: <expression>, …, <var_n>: <expression> },
pipeline: [ <pipeline to run> ],
as: <output array field>
}
}

$lookup acepta un documento con estos campos:

Campo
Descripción

Especifica la colección externa en la misma base de datos que se unirá a la colección local. La colección externa no se puede fragmentar (consulte Restricciones de colecciones fragmentadas).

Especifica los documentos locales localField para realizar una coincidencia de igualdad con los documentos extranjeros foreignField.

Si un documento local no contiene un localField valor, utiliza $lookup un null valor para la coincidencia.

Especifica los foreignField de los documentos foráneos para realizar una coincidencia exacta con los localField de los documentos locales.

Si un documento foráneo no contiene un valor foreignField, $lookup utiliza un valor null para la coincidencia.

Opcional. Especifica las variables que se usarán en las etapas del pipeline. Utilice las expresiones de variable para acceder a los campos del documento que se introducen pipeline en.

Para referenciar variables en las etapas de un pipeline, utiliza la sintaxis "$$<variable>".

Se puede acceder a las variables let por las etapas de la pipeline, incluidas las etapas adicionales$lookup anidadas en el pipeline.

  • Una etapa $match requiere el uso de un operador $expr para acceder a las variables. El operador $expr permite el uso de expresiones de agregación dentro de la sintaxis de $match.

    Los operadores de comparación $eq, $lt, $lte, $gt y $gte colocados en un operador $expr pueden utilizar un índice en la colección from referenciada en una etapa $lookup. Limitaciones:

    • Los índices solo pueden utilizarse para comparaciones entre campos y constantes, por lo que el operando let debe resolverse en una constante.

      Por ejemplo, una comparación entre $a y un valor constante puede utilizar un índice, pero una comparación entre $a y $b no puede.

    • Los índices no se utilizan para comparaciones donde el operando let se resuelve en un valor vacío o faltante.

    • Los índices multiclave no se utilizan.

  • Otras etapas (no$match) de la pipeline no requieren un operador $exprpara acceder a las variables.

Especifica el valor pipeline que se ejecutará en la colección externa. El valor pipeline devuelve los documentos de la colección externa. Para devolver todos los documentos, especifique un valor pipeline [] vacío.

El pipeline no puede incluir las etapas de $out o $merge.

El pipeline no puede acceder directamente a los campos del documento. En su lugar, defina variables para los campos del documento mediante la opción let y luego haga referencia a las variables en las pipeline etapas.

Para referenciar variables en las etapas de un pipeline, utiliza la sintaxis "$$<variable>".

Se puede acceder a las variables let por las etapas de la pipeline, incluidas las etapas adicionales$lookup anidadas en el pipeline.

  • Una etapa $match requiere el uso de un operador $expr para acceder a las variables. El operador $expr permite el uso de expresiones de agregación dentro de la sintaxis de $match.

    Los operadores de comparación $eq, $lt, $lte, $gt y $gte colocados en un operador $expr pueden utilizar un índice en la colección from referenciada en una etapa $lookup. Limitaciones:

    • Los índices solo pueden utilizarse para comparaciones entre campos y constantes, por lo que el operando let debe resolverse en una constante.

      Por ejemplo, una comparación entre $a y un valor constante puede utilizar un índice, pero una comparación entre $a y $b no puede.

    • Los índices no se utilizan para comparaciones donde el operando let se resuelve en un valor vacío o faltante.

    • Los índices multiclave no se utilizan.

  • Otras etapas (no$match) de la pipeline no requieren un operador $exprpara acceder a las variables.

Especifica el nombre del nuevo campo de arreglo que se debe agregar a los documentos externos. El nuevo campo arreglo contiene los documentos coincidentes de la colección externa. Si el nombre especificado ya existe en el documento externo, el campo existente se sobrescribe.

La operación corresponde a esta instrucción pseudo-SQL:

SELECT *, <output array field>
FROM localCollection
WHERE <output array field> IN (
SELECT <documents as determined from the pipeline>
FROM <foreignCollection>
WHERE <foreignCollection.foreignField> = <localCollection.localField>
AND <pipeline match condition>
);

Vea este ejemplo:

Si realizas una agregación que implique varias vistas, como con $lookup o $graphLookup, las vistas deben tener la misma intercalación.

No se pueden incluir las etapas$outni$mergeen la etapa$lookup. Es decir, al especificar una canalización para la colección unida, no se puede incluir ninguna de las etapas en el campo pipeline.

{
$lookup:
{
from: <collection to join>,
let: { <var_1>: <expression>, …, <var_n>: <expression> },
pipeline: [ <pipeline to execute on the joined collection> ], // Cannot include $out or $merge
as: <output array field>
}
}

En la etapa,$lookup la from colección no se puede fragmentar. Sin embargo, la colección en la que se ejecuta el método sí se puede fragmentar. En concreto, en este aggregate() ejemplo:

db.collection.aggregate([
{ $lookup: { from: "fromCollection", ... } }
])
  • El collection se puede fragmentar.

  • El fromCollection no se puede fragmentar.

Para unir una colección fragmentada con una colección no fragmentada, ejecute la agregación en la colección fragmentada y busque la colección no fragmentada. Por ejemplo:

db.shardedCollection.aggregate([
{ $lookup: { from: "unshardedCollection", ... } }
])

Alternativamente, o para unir múltiples colecciones fragmentadas, considere:

  • Modificar las aplicaciones cliente para realizar búsquedas manuales en lugar de utilizar la $lookup etapa de agregación.

  • Si es posible, utilice un modelo de datos integrado que elimine la necesidad de unir colecciones.

$lookup el rendimiento depende del tipo de operación que se realice. Consulta la siguiente tabla para las consideraciones de rendimiento de las diferentes operaciones de $lookup.

$lookup Operación
Consideraciones sobre el rendimiento
  • $lookup Las operaciones que realizan coincidencias exactas con una sola unión funcionan mejor cuando la colección externa contiene un índice en el foreignField.

    IMPORTANTE: si no existe un índice de apoyo en el foreignField, es probable que una operación $lookup que realice una coincidencia exacta con una sola unión tenga un rendimiento deficiente.

  • $lookup operaciones que contienen subqueries no correlacionadas funcionan mejor cuando el pipeline interno puede acceder a un índice de la colección externa.

  • MongoDB solo necesita ejecutar una vez la subquery $lookup antes de almacenar en caché la query porque no hay relación entre las colecciones de origen y las externas. La subquery no se basa en ningún valor de la colección de origen. Este comportamiento mejora el rendimiento para las ejecuciones posteriores de la operación $lookup.

  • $lookup operaciones que contienen subqueries correlacionadas tienen un mejor rendimiento cuando se aplican las siguientes condiciones:

    • La colección foránea contiene un índice en el foreignField.

    • La colección foránea contiene un índice que hace referencia a la pipeline interna.

  • Si tu pipeline pasa una gran cantidad de documentos a la query$lookup, las siguientes estrategias pueden mejorar el rendimiento:

    • Reduce el número de documentos que MongoDB pasa a la query $lookup. Por ejemplo, establece un filtro más estricto durante la etapa $match.

    • Ejecute la pipeline interna de la sub-query $lookup como query independiente y use $out para crear una colección temporal. Luego, ejecute una coincidencia exacta con una sola unión.

    • Reconsidere el esquema de los datos para asegurarse de que sea óptimo para el caso de uso.

Para estrategias generales de rendimiento, consulta las Estrategias de indexación y Optimización de query.

Importante

El uso excesivo de $lookup en una consulta puede ralentizar el rendimiento. Para evitar múltiples $lookup etapas de, considere un modelo de datos integrado para optimizar el rendimiento de la consulta.

Cree una colección orders con estos documentos:

db.orders.insertMany( [
{ "_id" : 1, "item" : "almonds", "price" : 12, "quantity" : 2 },
{ "_id" : 2, "item" : "pecans", "price" : 20, "quantity" : 1 },
{ "_id" : 3 }
] )

Cree otra colección inventory con estos documentos:

db.inventory.insertMany( [
{ "_id" : 1, "sku" : "almonds", "description": "product 1", "instock" : 120 },
{ "_id" : 2, "sku" : "bread", "description": "product 2", "instock" : 80 },
{ "_id" : 3, "sku" : "cashews", "description": "product 3", "instock" : 60 },
{ "_id" : 4, "sku" : "pecans", "description": "product 4", "instock" : 70 },
{ "_id" : 5, "sku": null, "description": "Incomplete" },
{ "_id" : 6 }
] )

La siguiente operación de agregación en la colección orders une los documentos de orders con los documentos de la colección inventory utilizando los campos item de la colección orders y el campo sku de la colección inventory:

db.orders.aggregate( [
{
$lookup:
{
from: "inventory",
localField: "item",
foreignField: "sku",
as: "inventory_docs"
}
}
] )

La operación devuelve estos documentos:

{
"_id" : 1,
"item" : "almonds",
"price" : 12,
"quantity" : 2,
"inventory_docs" : [
{ "_id" : 1, "sku" : "almonds", "description" : "product 1", "instock" : 120 }
]
}
{
"_id" : 2,
"item" : "pecans",
"price" : 20,
"quantity" : 1,
"inventory_docs" : [
{ "_id" : 4, "sku" : "pecans", "description" : "product 4", "instock" : 70 }
]
}
{
"_id" : 3,
"inventory_docs" : [
{ "_id" : 5, "sku" : null, "description" : "Incomplete" },
{ "_id" : 6 }
]
}

La operación corresponde a esta instrucción pseudo-SQL:

SELECT *, inventory_docs
FROM orders
WHERE inventory_docs IN (
SELECT *
FROM inventory
WHERE sku = orders.item
);

Para obtener más información, consulta Consideraciones sobre el rendimiento de la coincidencia exacta.

Si el localField es un arreglo, puedes comparar los elementos del arreglo contra un escalar foreignField sin una etapa de $unwind.

Por ejemplo, cree una colección de ejemplo classes con estos documentos:

db.classes.insertMany( [
{ _id: 1, title: "Reading is ...", enrollmentlist: [ "giraffe2", "pandabear", "artie" ], days: ["M", "W", "F"] },
{ _id: 2, title: "But Writing ...", enrollmentlist: [ "giraffe1", "artie" ], days: ["T", "F"] }
] )

Cree otra colección members con estos documentos:

db.members.insertMany( [
{ _id: 1, name: "artie", joined: new Date("2016-05-01"), status: "A" },
{ _id: 2, name: "giraffe", joined: new Date("2017-05-01"), status: "D" },
{ _id: 3, name: "giraffe1", joined: new Date("2017-10-01"), status: "A" },
{ _id: 4, name: "panda", joined: new Date("2018-10-11"), status: "A" },
{ _id: 5, name: "pandabear", joined: new Date("2018-12-01"), status: "A" },
{ _id: 6, name: "giraffe2", joined: new Date("2018-12-01"), status: "D" }
] )

La siguiente operación de agregación une documentos de la colección classes con la colección members, emparejando el campo enrollmentlist con el campo name:

db.classes.aggregate( [
{
$lookup:
{
from: "members",
localField: "enrollmentlist",
foreignField: "name",
as: "enrollee_info"
}
}
] )

La operación devuelve lo siguiente:

{
"_id" : 1,
"title" : "Reading is ...",
"enrollmentlist" : [ "giraffe2", "pandabear", "artie" ],
"days" : [ "M", "W", "F" ],
"enrollee_info" : [
{ "_id" : 1, "name" : "artie", "joined" : ISODate("2016-05-01T00:00:00Z"), "status" : "A" },
{ "_id" : 5, "name" : "pandabear", "joined" : ISODate("2018-12-01T00:00:00Z"), "status" : "A" },
{ "_id" : 6, "name" : "giraffe2", "joined" : ISODate("2018-12-01T00:00:00Z"), "status" : "D" }
]
}
{
"_id" : 2,
"title" : "But Writing ...",
"enrollmentlist" : [ "giraffe1", "artie" ],
"days" : [ "T", "F" ],
"enrollee_info" : [
{ "_id" : 1, "name" : "artie", "joined" : ISODate("2016-05-01T00:00:00Z"), "status" : "A" },
{ "_id" : 3, "name" : "giraffe1", "joined" : ISODate("2017-10-01T00:00:00Z"), "status" : "A" }
]
}

El $mergeObjects operador combina múltiples documentos en un único documento.

Cree una colección orders con estos documentos:

db.orders.insertMany( [
{ "_id" : 1, "item" : "almonds", "price" : 12, "quantity" : 2 },
{ "_id" : 2, "item" : "pecans", "price" : 20, "quantity" : 1 }
] )

Cree otra colección items con estos documentos:

db.items.insertMany( [
{ "_id" : 1, "item" : "almonds", description: "almond clusters", "instock" : 120 },
{ "_id" : 2, "item" : "bread", description: "raisin and nut bread", "instock" : 80 },
{ "_id" : 3, "item" : "pecans", description: "candied pecans", "instock" : 60 }
] )

La siguiente operación primero utiliza la etapa $lookup para unir las dos colecciones por los campos item y luego utiliza $mergeObjects en el $replaceRoot para fusionar los documentos combinados de items y orders:

db.orders.aggregate( [
{
$lookup: {
from: "items",
localField: "item", // field in the orders collection
foreignField: "item", // field in the items collection
as: "fromItems"
}
},
{
$replaceRoot: { newRoot: { $mergeObjects: [ { $arrayElemAt: [ "$fromItems", 0 ] }, "$$ROOT" ] } }
},
{ $project: { fromItems: 0 } }
] )

La operación devuelve estos documentos:

{
_id: 1,
item: 'almonds',
description: 'almond clusters',
instock: 120,
price: 12,
quantity: 2
},
{
_id: 2,
item: 'pecans',
description: 'candied pecans',
instock: 60,
price: 20,
quantity: 1
}

Las canalizaciones se pueden ejecutar en una colección unida e incluir múltiples condiciones de unión.

Una condición de unión puede hacer referencia a un campo de la colección local donde aggregate() se ejecutó el método y a un campo de la colección unida. Esto permite una subconsulta correlacionada entre ambas colecciones.

MongoDB 5.0 soporta los subquery correlacionados concisos.

Cree una colección orders con estos documentos:

db.orders.insertMany( [
{ "_id" : 1, "item" : "almonds", "price" : 12, "ordered" : 2 },
{ "_id" : 2, "item" : "pecans", "price" : 20, "ordered" : 1 },
{ "_id" : 3, "item" : "cookies", "price" : 10, "ordered" : 60 }
] )

Cree otra colección warehouses con estos documentos:

db.warehouses.insertMany( [
{ "_id" : 1, "stock_item" : "almonds", warehouse: "A", "instock" : 120 },
{ "_id" : 2, "stock_item" : "pecans", warehouse: "A", "instock" : 80 },
{ "_id" : 3, "stock_item" : "almonds", warehouse: "B", "instock" : 60 },
{ "_id" : 4, "stock_item" : "cookies", warehouse: "B", "instock" : 40 },
{ "_id" : 5, "stock_item" : "cookies", warehouse: "A", "instock" : 80 }
] )

El siguiente ejemplo:

  • Utiliza una sub-query correlacionada con una unión en los campos orders.item y warehouse.stock_item.

  • Garantiza que la cantidad del artículo en inventario pueda abastecer la cantidad pedida.

db.orders.aggregate( [
{
$lookup:
{
from: "warehouses",
let: { order_item: "$item", order_qty: "$ordered" },
pipeline: [
{ $match:
{ $expr:
{ $and:
[
{ $eq: [ "$stock_item", "$$order_item" ] },
{ $gte: [ "$instock", "$$order_qty" ] }
]
}
}
},
{ $project: { stock_item: 0, _id: 0 } }
],
as: "stockdata"
}
}
] )

La operación devuelve estos documentos:

{
_id: 1,
item: 'almonds',
price: 12,
ordered: 2,
stockdata: [
{ warehouse: 'A', instock: 120 },
{ warehouse: 'B', instock: 60 }
]
},
{
_id: 2,
item: 'pecans',
price: 20,
ordered: 1,
stockdata: [ { warehouse: 'A', instock: 80 } ]
},
{
_id: 3,
item: 'cookies',
price: 10,
ordered: 60,
stockdata: [ { warehouse: 'A', instock: 80 } ]
}

La operación corresponde a esta instrucción pseudo-SQL:

SELECT *, stockdata
FROM orders
WHERE stockdata IN (
SELECT warehouse, instock
FROM warehouses
WHERE stock_item = orders.item
AND instock >= orders.ordered
);

Los operadores de comparación $eq, $lt, $lte, $gt y $gte colocados en un operador $expr pueden utilizar un índice en la colección from mencionada en una etapa $lookup. Limitaciones:

  • Los índices solo pueden utilizarse para comparaciones entre campos y constantes, por lo que el operando let debe resolverse en una constante.

    Por ejemplo, una comparación entre $a y un valor constante puede utilizar un índice, pero una comparación entre $a y $b no puede.

  • Los índices no se utilizan para comparaciones donde el operando let se resuelve en un valor vacío o faltante.

  • Los índices multiclave no se utilizan.

Por ejemplo, si el índice { stock_item: 1, instock: 1 } existe en la colección warehouses:

  • La coincidencia exacta en el campo warehouses.stock_item utiliza el índice.

  • La parte de rango de la query sobre el campo warehouses.instock también utiliza el campo indexado en el índice compuesto.

Tip

Una etapa de canalización $lookup de agregación puede ejecutar una canalización en la colección unida, lo que permite subconsultas no correlacionadas. Una subconsulta no correlacionada no hace referencia a los campos del documento unido.

Nota

A partir de MongoDB 5.0, para un subquery no correlacionado en una etapa de la pipeline de $lookup que contenga una etapa $sample, el operador $sampleRate o el operador $rand, el subquery siempre se ejecuta nuevamente si se repite. Anteriormente, según el tamaño del resultado del subquery, se almacenaba en caché o el subquery se ejecutaba nuevamente.

Cree una colección absences con estos documentos:

db.absences.insertMany( [
{ "_id" : 1, "student" : "Ann Aardvark", sickdays: [ new Date ("2018-05-01"),new Date ("2018-08-23") ] },
{ "_id" : 2, "student" : "Zoe Zebra", sickdays: [ new Date ("2018-02-01"),new Date ("2018-05-23") ] },
] )

Cree otra colección holidays con estos documentos:

db.holidays.insertMany( [
{ "_id" : 1, year: 2018, name: "New Years", date: new Date("2018-01-01") },
{ "_id" : 2, year: 2018, name: "Pi Day", date: new Date("2018-03-14") },
{ "_id" : 3, year: 2018, name: "Ice Cream Day", date: new Date("2018-07-15") },
{ "_id" : 4, year: 2017, name: "New Years", date: new Date("2017-01-01") },
{ "_id" : 5, year: 2017, name: "Ice Cream Day", date: new Date("2017-07-16") }
] )

La siguiente operación une la colección absences con la información de las vacaciones de 2018 de la colección holidays:

db.absences.aggregate( [
{
$lookup:
{
from: "holidays",
pipeline: [
{ $match: { year: 2018 } },
{ $project: { _id: 0, date: { name: "$name", date: "$date" } } },
{ $replaceRoot: { newRoot: "$date" } }
],
as: "holidays"
}
}
] )

La operación devuelve lo siguiente:

{
_id: 1,
student: 'Ann Aardvark',
sickdays: [
ISODate("2018-05-01T00:00:00.000Z"),
ISODate("2018-08-23T00:00:00.000Z")
],
holidays: [
{ name: 'New Years', date: ISODate("2018-01-01T00:00:00.000Z") },
{ name: 'Pi Day', date: ISODate("2018-03-14T00:00:00.000Z") },
{ name: 'Ice Cream Day', date: ISODate("2018-07-15T00:00:00.000Z")
}
]
},
{
_id: 2,
student: 'Zoe Zebra',
sickdays: [
ISODate("2018-02-01T00:00:00.000Z"),
ISODate("2018-05-23T00:00:00.000Z")
],
holidays: [
{ name: 'New Years', date: ISODate("2018-01-01T00:00:00.000Z") },
{ name: 'Pi Day', date: ISODate("2018-03-14T00:00:00.000Z") },
{ name: 'Ice Cream Day', date: ISODate("2018-07-15T00:00:00.000Z")
}
]
}

La operación corresponde a esta instrucción pseudo-SQL:

SELECT *, holidays
FROM absences
WHERE holidays IN (
SELECT name, date
FROM holidays
WHERE year = 2018
);

Para obtener más información, consulta Consideraciones sobre el rendimiento de subquery no correlacionado.

Nuevo en la versión 5.0.

A partir de MongoDB 5.0, una etapa de $lookup de la pipeline de agregación admite una sintaxis concisa de subquery correlacionado que mejora las uniones entre colecciones. La nueva sintaxis concisa remueve el requisito de una coincidencia exacta en los campos externos y locales dentro de un operador $expr en una etapa $match.

Cree una colección restaurants:

db.restaurants.insertMany( [
{
_id: 1,
name: "American Steak House",
food: [ "filet", "sirloin" ],
beverages: [ "beer", "wine" ]
},
{
_id: 2,
name: "Honest John Pizza",
food: [ "cheese pizza", "pepperoni pizza" ],
beverages: [ "soda" ]
}
] )

Crea otra colección orders con pedidos de comida y bebidas opcionales:

db.orders.insertMany( [
{
_id: 1,
item: "filet",
restaurant_name: "American Steak House"
},
{
_id: 2,
item: "cheese pizza",
restaurant_name: "Honest John Pizza",
drink: "lemonade"
},
{
_id: 3,
item: "cheese pizza",
restaurant_name: "Honest John Pizza",
drink: "soda"
}
] )

El siguiente ejemplo:

  • Une las colecciones orders y restaurants al emparejar el localFieldorders.restaurant_name con el foreignField restaurants.name. La coincidencia se realiza antes de que se ejecute pipeline.

  • Realiza una coincidencia de arreglo $in entre los campos orders.drink y restaurants.beverages a los que se accede utilizando $$orders_drink y $beverages respectivamente.

db.orders.aggregate( [
{
$lookup: {
from: "restaurants",
localField: "restaurant_name",
foreignField: "name",
let: { orders_drink: "$drink" },
pipeline: [ {
$match: {
$expr: { $in: [ "$$orders_drink", "$beverages" ] }
}
} ],
as: "matches"
}
}
] )

Hay una coincidencia para el valor soda en los campos orders.drink y restaurants.beverages. Esta salida muestra la matriz matches y contiene todos los campos unidos de la colección restaurants para la coincidencia:

{
"_id" : 1, "item" : "filet",
"restaurant_name" : "American Steak House",
"matches" : [ ]
}
{
"_id" : 2, "item" : "cheese pizza",
"restaurant_name" : "Honest John Pizza",
"drink" : "lemonade",
"matches" : [ ]
}
{
"_id" : 3, "item" : "cheese pizza",
"restaurant_name" : "Honest John Pizza",
"drink" : "soda",
"matches" : [ {
"_id" : 2, "name" : "Honest John Pizza",
"food" : [ "cheese pizza", "pepperoni pizza" ],
"beverages" : [ "soda" ]
} ]
}

Antes de la introducción de subconsultas correlacionadas concisas, era necesario utilizar una coincidencia de igualdad$eqentre el campo local y el campo unido en el operador$expren la etapa pipeline $lookupcomo se muestra en Realizar múltiples uniones y una subconsulta correlacionada con $lookup.

Este ejemplo utiliza la sintaxis detallada de las versiones de MongoDB anteriores a la 5.0 y arroja los mismos resultados que el ejemplo conciso anterior:

db.orders.aggregate( [
{
$lookup: {
from: "restaurants",
let: { orders_restaurant_name: "$restaurant_name",
orders_drink: "$drink" },
pipeline: [ {
$match: {
$expr: {
$and: [
{ $eq: [ "$$orders_restaurant_name", "$name" ] },
{ $in: [ "$$orders_drink", "$beverages" ] }
]
}
}
} ],
as: "matches"
}
}
] )

Los ejemplos anteriores corresponden a esta instrucción pseudo-SQL:

SELECT *, matches
FROM orders
WHERE matches IN (
SELECT *
FROM restaurants
WHERE restaurants.name = orders.restaurant_name
AND restaurants.beverages = orders.drink
);

Para obtener más información, consulta Consideraciones sobre el rendimiento de los subquery correlacionados.

Volver

$listSessions

En esta página