Definición
$lookupCambiado en la versión 8.0.
Performs a left outer join to a collection in the same database to filter in documents from the foreign collection for processing. The
$lookupstage adds a new array field to each input document. The new array field contains the matching documents from the foreign collection. The$lookupstage passes these reshaped documents to the next stage.A partir de MongoDB,5.1 puede usar con colecciones
$lookupfragmentadas.Para combinar elementos de dos colecciones diferentes, utiliza la plataforma de
$unionWithdel pipeline.Importante
$lookupperformance, as with any other query performance, depends on the operation type and whether the foreign field is indexed. Unindexed or correlated-subquery$lookupoperations on large collections can slow down query performance. To reduce reliance on$lookup, consider an embedded data model to store related data in a single collection.For details on
$lookupperformance by operation type, see Performance Considerations.
Compatibilidad
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.
Sintaxis
The $lookup stage syntax:
{ $lookup: { from: <collection to join>, localField: <field from the input documents>, foreignField: <field from the documents of the "from" collection>, let: { <var_1>: <expression>, …, <var_n>: <expression> }, pipeline: [ <pipeline to run> ], as: <output array field> } }
The $lookup accepts a document with these fields:
Campo | Necesidad | Descripción |
|---|---|---|
Requerido | Especifica la colección foránea en la misma base de datos para unirse a la colección local. Es posible en algunos casos extremos sustituir A partir de MongoDB 5.1, la colección | |
Opcional si se especifica | Specifies the field from the documents input to the | |
Opcional si se especifica | Especifica los If a foreign document does not contain a | |
Opcional | Specifies variables to use in the pipeline stages. Use the variable expressions to access the fields from the local collection's documents that are input to the To reference variables in pipeline stages, use the The let variables can be accessed by the stages in the pipeline, including additional
| |
Opcional si se especifican | Especifica el El The To reference variables in pipeline stages, use the The let variables can be accessed by the stages in the pipeline, including additional
| |
Requerido | 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 |
Coincidencia exacta con una única condición de unión
To perform an equality match between a field from the input documents with a field from the documents of the foreign collection, the $lookup stage has this syntax:
{ $lookup: { from: <collection to join>, localField: <field from the input documents>, foreignField: <field from the documents of the "from" collection>, pipeline: [ <pipeline to run> ], as: <output array field> } }
Nota
En este ejemplo, pipeline es opcional y se ejecuta después de la etapa de igualdad local y foránea.
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:
Condiciones de unión y sub-query en una colección foránea
MongoDB admite:
Ejecución de una pipeline en una colección externa.
Múltiples condiciones de combinación.
Subconsultas correlacionadas y no correlacionadas.
In MongoDB, an uncorrelated subquery means that every input document returns the same result. A correlated subquery is a pipeline in a $lookup stage that uses the local or input collection's fields to return results correlated to each incoming document.
Nota
A partir de MongoDB 5.0, para una subconsulta no correlacionada en una etapa de canalización$lookupque contiene una etapa$sample, el operador$sampleRateo el operador$rand, la subconsulta siempre se ejecuta de nuevo si se repite. Anteriormente, dependiendo del tamaño de la salida de la subconsulta, esta se almacenaba en caché o se volvía a ejecutar.
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.
To perform correlated and uncorrelated subqueries with two collections, and perform other join conditions besides a single equality match, use this $lookup syntax:
{ $lookup: { from: <foreign collection>, let: { <var_1>: <expression>, …, <var_n>: <expression> }, pipeline: [ <pipeline to run on foreign collection> ], as: <output array field> } }
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:
Subconsultas correlacionadas utilizando una sintaxis concisa
Nuevo en la versión 5.0.
A partir de MongoDB 5.0, puedes usar una sintaxis concisa para una sub-query correlacionada. Las sub-query correlacionadas hacen referencia a campos de documentos de una colección foránea y de la colección "local" en la que se ejecutó el método aggregate().
The following new concise syntax removes the requirement for an equality match on the foreign and local fields inside an $expr operator:
{ $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> } }
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:
Comportamiento
Colecciones encriptadas
A partir de MongoDB,8.1 puede hacer referencia a varias colecciones cifradas en una etapa. Sin $lookup embargo, $lookup no admite:
Utilizando un campo cifrado como campo de unión en el
localFieldoforeignField.Nota
Para los controladores que usan cifrado a nivel de campo del lado del cliente, puedes usar un campo cifrado como campo de unión solo si estás realizando una operación de unión automática.
Vistas e intercalación
If performing an aggregation that involves multiple views, such as with $lookup or $graphLookup, the views must have the same collation.
Restricciones
You cannot include the $out or the $merge stage in the $lookup stage. That is, when specifying a pipeline for the foreign collection, you cannot include either stage in the pipeline field.
{ $lookup: { from: <collection to join>, let: { <var_1>: <expression>, …, <var_n>: <expression> }, pipeline: [ <pipeline to execute on the foreign collection> ], // Cannot include $out or $merge as: <output array field> } }
Soporte para MongoDB Search
A partir de MongoDB,6.0 puede especificar la etapa MongoDB Search $search o en $searchMeta la $lookup canalización para buscar colecciones en el clúster Atlas. La $search etapa o debe ser la primera etapa dentro de la $searchMeta $lookup canalización.
For example, when you Join Conditions and Subqueries on a Foreign Collection or run Correlated Subqueries Using Concise Syntax, you can specify $search or $searchMeta inside the pipeline as shown below:
To see an example of $lookup with $search, see the MongoDB Search tutorial Run a MongoDB Search $search Query Using $lookup.
Colecciones fragmentadas
Starting in MongoDB 5.1, you can specify sharded collections in the from parameter of $lookup stages.
A partir de MongoDB 8.0, puedes usar la etapa $lookup dentro de una transacción mientras apunta a una colección fragmentada.
Motor de ejecución de query basado en ranuras
A partir de la 6.0 versión, MongoDB puede usar el motor de consulta de ejecución basado en ranuras para ejecutar $lookup etapas si todas las etapas anteriores en la canalización también pueden ser ejecutadas por el motor de ejecución basado en ranuras y ninguna de las siguientes condiciones es verdadera:
La operación
$lookupejecuta una pipeline en una colección foránea. Para ver un ejemplo de este tipo de operación, consulta Condiciones de unión y subconsultas en una colección foránea.Los
localFieldoforeignFieldde$lookupespecifican componentes numéricos. Por ejemplo:{ localField: "restaurant.0.review" }.El campo
fromde cualquier$lookupen el pipeline especifica una vista o una colección fragmentada.
Para obtener más información, consulta $lookupOptimización.
Consideraciones sobre el rendimiento
$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 |
|---|---|
| |
| |
|
Para estrategias generales de rendimiento, consulta las Estrategias de indexación y Optimización de query.
Ejemplos
Los ejemplos de esta página utilizan datos del conjunto de datos de muestra sample_mflix. Para obtener más información sobre cómo cargar este conjunto de datos en la implementación autogestionada de MongoDB, consultar Cargar el conjunto de datos de muestra. Si se realizó alguna modificación en las bases de datos de muestra, es posible que se deban descartar y volver a crear las bases de datos para ejecutar los ejemplos de esta página.
Realice una única unión de igualdad con $lookup
La siguiente operación de agregación primero filtra la colección movies para películas con un runtime superior a 1000, y luego se une con la colección comments en los campos _id y movie_id:
db.movies.aggregate( [ { $match: { runtime: { $gt: 1000 } } }, { $lookup: { from: "comments", localField: "_id", foreignField: "movie_id", as: "movie_comments" } }, { $project: { _id: 0, title: 1, year: 1, "movie_comments.name": 1, "movie_comments.text": 1, "movie_comments.date": 1 } } ] )
[ { title: 'Centennial', year: 1978, movie_comments: [ { name: 'Ellaria Sand', text: 'Excepturi nam nam eum possimus aspernatur autem. Quis nulla optio praesentium ut distinctio explicabo.', date: ISODate('1995-08-18T03:01:50.000Z') } ] }, { title: 'Baseball', year: 1994, movie_comments: [] } ]
La operación corresponde a esta instrucción pseudo-SQL:
SELECT *, movie_comments FROM movies WHERE movie_comments IN ( SELECT * FROM comments WHERE movie_id = movies._id );
Para obtener más información, consulta Consideraciones sobre el rendimiento de la coincidencia exacta.
Utiliza $lookup con un arreglo
Si el localField es un arreglo, puedes comparar los elementos del arreglo contra un escalar foreignField sin una etapa de $unwind.
La siguiente operación de agregación une la colección movies con la colección users, emparejando el campo de arreglo cast de movies con el campo escalar name de users:
db.movies.aggregate( [ { $match: { title: { $in: [ "Roger & Me", "The Sum of Us", "Centennial" ] } } }, { $lookup: { from: "users", localField: "cast", foreignField: "name", as: "cast_users" } }, { $project: { _id: 0, title: 1, year: 1, cast: 1, "cast_users.name": 1, "cast_users.email": 1 } }, { $sort: { year: 1 } } ] )
[ { cast: [ 'Raymond Burr', 'Barbara Carrera', 'Richard Chamberlain', 'Robert Conrad' ], title: 'Centennial', year: 1978, cast_users: [] }, { cast: [ 'Michael Moore', 'Roger B. Smith', 'Rhonda Britton', 'Fred Ross' ], title: 'Roger & Me', year: 1989, cast_users: [ { name: 'Michael Moore', email: 'michael_moore@fakegmail.com' } ] }, { cast: [ 'Jack Thompson', 'Russell Crowe', 'John Polson', 'Deborah Kennedy' ], title: 'The Sum of Us', year: 1994, cast_users: [ { name: 'Deborah Kennedy', email: 'deborah_kennedy@fakegmail.com' } ] } ]
Utiliza $lookup con $mergeObjects
El $mergeObjects operador combina múltiples documentos en un único documento.
The following operation uses $lookup to join the movies collection with the comments collection, then uses $mergeObjects in $replaceRoot to merge the first comment document with the movie document:
db.movies.aggregate( [ { $match: { runtime: { $gt: 1000 } } }, { $lookup: { from: "comments", localField: "_id", foreignField: "movie_id", as: "movie_comments" } }, { $replaceRoot: { newRoot: { $mergeObjects: [ { $arrayElemAt: [ "$movie_comments", 0 ] }, "$$ROOT" ] } } }, { $project: { _id: 0, title: 1, year: 1, genres: 1, name: 1, email: 1, text: 1, date: 1 } } ] )
[ { name: 'Ellaria Sand', email: 'indira_varma@gameofthron.es', text: 'Excepturi nam nam eum possimus aspernatur autem. Quis nulla optio praesentium ut distinctio explicabo.', date: ISODate('1995-08-18T03:01:50.000Z'), genres: [ 'Action', 'Adventure', 'Drama' ], title: 'Centennial', year: 1978 }, { genres: [ 'Documentary', 'History', 'Sport' ], title: 'Baseball', year: 1994 } ]
Utiliza múltiples condiciones de JOIN y una sub-query correlacionada
Las pipelines pueden ejecutarse en una colección externa e incluir múltiples condiciones de unión. El operador $expr permite condiciones de unión más complejas, incluidas las conjunciones y las coincidencias inexactas.
Una condición de unión puede referirse a un campo en la colección local en la que se ejecutó el método aggregate() y referirse a un campo en la colección extranjera. Esto permite una sub-query correlacionada entre ambas colecciones.
MongoDB 5.0 soporta los subquery correlacionados concisos.
El siguiente ejemplo:
Une las colecciones
moviesycommentsusando los campos_idymovie_id.Filtra los comentarios para incluir únicamente aquellos publicados después del año de estreno de la película.
db.movies.aggregate( [ { $match: { title: { $in: [ "Class Action", "Kafka", "Corpse Bride" ] } } }, { $lookup: { from: "comments", localField: "_id", foreignField: "movie_id", let: { movie_year: "$year" }, pipeline: [ { $match: { $expr: { $gt: [ { $year: "$date" }, "$$movie_year" ] } } }, { $project: { _id: 0, name: 1, date: 1 } } ], as: "post_release_comments" } }, { $project: { _id: 0, title: 1, year: 1, post_release_comments: 1 } } ] )
[ { year: 1991, title: 'Class Action', post_release_comments: [ { name: 'Khal Drogo', date: ISODate('2016-12-06T07:17:03.000Z') } ] }, { year: 1991, title: 'Kafka', post_release_comments: [ { name: 'Khal Drogo', date: ISODate('1998-05-10T03:10:20.000Z') } ] }, { year: 2005, title: 'Corpse Bride', post_release_comments: [] } ]
La operación corresponde a esta instrucción pseudo-SQL:
SELECT *, post_release_comments FROM movies WHERE post_release_comments IN ( SELECT name, date FROM comments WHERE movie_id = movies._id AND YEAR(date) > movies.year );
The $eq, $lt, $lte, $gt, and $gte comparison operators placed in an $expr operator can use an index on the from collection referenced in a $lookup stage. Limitations:
Los índices solo pueden utilizarse para comparaciones entre campos y constantes, por lo que el operando
letdebe resolverse en una constante.Por ejemplo, una comparación entre
$ay un valor constante puede utilizar un índice, pero una comparación entre$ay$bno puede.Los índices no se utilizan para comparaciones donde el operando
letse resuelve en un valor vacío o faltante.No se utilizan índices multiclave, parciales o dispersos.
Por ejemplo, si el índice { movie_id: 1 } existe en la colección comments:
- La coincidencia exacta en el campo
comments.movie_idutiliza el índice.
Realice una sub-query no correlacionada con $lookup
An aggregation pipeline $lookup stage can execute a pipeline on the foreign collection, which allows uncorrelated subqueries. An uncorrelated subquery does not reference the local document fields.
Nota
Starting in MongoDB 5.0, for an uncorrelated subquery in a $lookup pipeline stage containing a $sample stage, the $sampleRate operator, or the $rand operator, the subquery is always run again if repeated. Previously, depending on the subquery output size, either the subquery output was cached or the subquery was run again.
La siguiente operación une la colección users con las películas que tienen una duración superior a 1000 minutos, pertenecientes a la colección movies:
db.users.aggregate( [ { $match: { email: { $in: [ "mark_addy@gameofthron.es", "lena_headey@gameofthron.es" ] } } }, { $lookup: { from: "movies", pipeline: [ { $match: { runtime: { $gt: 1000 } } }, { $project: { _id: 0, title: 1, year: 1 } } ], as: "long_movies" } }, { $project: { _id: 0, name: 1, email: 1, long_movies: 1 } } ] )
[ { name: 'Robert Baratheon', email: 'mark_addy@gameofthron.es', long_movies: [ { title: 'Centennial', year: 1978 }, { title: 'Baseball', year: 1994 } ] }, { name: 'Cersei Lannister', email: 'lena_headey@gameofthron.es', long_movies: [ { title: 'Centennial', year: 1978 }, { title: 'Baseball', year: 1994 } ] } ]
La operación corresponde a esta instrucción pseudo-SQL:
SELECT *, long_movies FROM users WHERE long_movies IN ( SELECT title, year FROM movies WHERE runtime > 1000 );
Para obtener más información, consulta Consideraciones sobre el rendimiento de subquery no correlacionado.
Realice una sub-query correlacionada concisa con $lookup
Nuevo en la versión 5.0.
A partir de MongoDB,5.0 una etapa de canalización de $lookup agregación admite una sintaxis de subconsulta correlacionada concisa que mejora las uniones entre colecciones. La nueva sintaxis concisa elimina el requisito de una coincidencia de igualdad en los campos foráneos y locales dentro de un operador $expr $match en una etapa.
El siguiente ejemplo:
Joins the
moviesandcommentscollections by matching the localField_idwith the foreignFieldmovie_id. The match is performed before thepipelineis run.Filtra los comentarios para incluir solo aquellos publicados después del año de estreno de la película, accediendo respectivamente mediante
$$movie_yeary$date.
db.movies.aggregate( [ { $match: { title: { $in: [ "I Don't Kiss", "Lucky Luke", "Mississippi Masala" ] } } }, { $lookup: { from: "comments", localField: "_id", foreignField: "movie_id", let: { movie_year: "$year" }, pipeline: [ { $match: { $expr: { $gt: [ { $year: "$date" }, "$$movie_year" ] } } }, { $project: { _id: 0, name: 1, date: 1 } } ], as: "post_release_comments" } }, { $project: { _id: 0, title: 1, year: 1, post_release_comments: 1 } } ] )
[ { title: "I Don't Kiss", year: 1991, post_release_comments: [ { name: 'Brandon Hardy', date: ISODate('2016-09-18T11:11:34.000Z') } ] }, { title: 'Lucky Luke', year: 1991, post_release_comments: [ { name: 'Kelsey Smith', date: ISODate('2010-01-13T17:55:01.000Z') } ] }, { title: 'Mississippi Masala', year: 1991, post_release_comments: [ { name: 'Phillip Collins', date: ISODate('2010-05-13T08:04:22.000Z') } ] } ]
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.movies.aggregate( [ { $match: { title: { $in: [ "I Don't Kiss", "Lucky Luke", "Mississippi Masala" ] } } }, { $lookup: { from: "comments", let: { movie_id: "$_id", movie_year: "$year" }, pipeline: [ { $match: { $expr: { $and: [ { $eq: [ "$movie_id", "$$movie_id" ] }, { $gt: [ { $year: "$date" }, "$$movie_year" ] } ] } } }, { $project: { _id: 0, name: 1, date: 1 } } ], as: "post_release_comments" } }, { $project: { _id: 0, title: 1, year: 1, post_release_comments: 1 } } ] )
[ { title: "I Don't Kiss", year: 1991, post_release_comments: [ { name: 'Brandon Hardy', date: ISODate('2016-09-18T11:11:34.000Z') } ] }, { title: 'Lucky Luke', year: 1991, post_release_comments: [ { name: 'Kelsey Smith', date: ISODate('2010-01-13T17:55:01.000Z') } ] }, { title: 'Mississippi Masala', year: 1991, post_release_comments: [ { name: 'Phillip Collins', date: ISODate('2010-05-13T08:04:22.000Z') } ] } ]
Los ejemplos anteriores corresponden a esta instrucción pseudo-SQL:
SELECT *, post_release_comments FROM movies WHERE post_release_comments IN ( SELECT * FROM comments WHERE comments.movie_id = movies._id AND YEAR(comments.date) > movies.year );
Para obtener más información, consulta Consideraciones sobre el rendimiento de los subquery correlacionados.
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" } ] )
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; } }
La siguiente clase Comment modela los documentos en la colección sample_mflix.comments:
[] public class Comment { [] public ObjectId Id { get; set; } [] public ObjectId MovieId { get; set; } [] public string Text { get; set; } = null!; }
La siguiente clase LookupResult almacena la salida de la etapa $lookup:
[] public class LookupResult { [] public ObjectId Id { get; set; } [] public string Title { get; set; } = null!; public List<Comment> Comments { get; set; } = []; }
To use the MongoDB .NET/C# driver to add a $lookup stage to an aggregation pipeline, call the UnionWith() method on a PipelineDefinition object.
El siguiente ejemplo crea una etapa de pipeline que realiza una unión externa izquierda entre las colecciones movies y comments. El código une el campo Id de cada documento Movie al campo MovieId en los documentos Comment. Los comentarios de cada película se almacenan en un campo llamado Comments en cada documento LookupResult.
var commentCollection = _client .GetDatabase("sample_mflix") .GetCollection<Comment>("comments"); var pipeline = new EmptyPipelineDefinition<Movie>() .Lookup<Movie, Movie, Comment, LookupResult>( foreignCollection: commentCollection, localField: m => m.Id, foreignField: c => c.MovieId, @as: r => r.Comments);
Los ejemplos de Node.js 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, consulte Primeros pasos en la documentación del controlador de MongoDB Node.js.
Para utilizar el controlador de MongoDB Node.js para agregar una etapa de $lookup a una canalización de agregación, utilice el Operador $lookup en un objeto de canalización.
El siguiente ejemplo crea una etapa de pipeline que realiza una unión externa izquierda entre las colecciones movies y comments. El código une el campo _id de cada documento movie al campo movie_id en los documentos comment. El campo comments almacena los comentarios de cada película en cada documento movie. A continuación, el ejemplo ejecuta la pipeline de agregación:
const pipeline = [ { $lookup: { from: "comments", localField: "_id", foreignField: "movie_id", as: "comments" } } ]; const cursor = collection.aggregate(pipeline); return cursor;