Definição
$lookupAlterado na versão 5.1.
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 do MongoDB 5.1, é possível usar
$lookupcom coleções fragmentadas.Para combinar elementos de duas coleções diferentes, use o estágio de pipeline
$unionWith.Importante
$lookupo desempenho, como em qualquer outro desempenho de query, depende do tipo de operação e se o campo estrangeiro está índice. Operações$lookupnão indexadas ou de subquery correlacionada em coleções grandes podem reduzir o desempenho da query. Para reduzir a dependência de$lookup, considere um modelo de dados incorporado para armazenar dados relacionados em uma única coleção.For details on
$lookupperformance by operation type, see Performance Considerations.
Compatibilidade
Você pode utilizar o $lookup para implantações hospedadas nos seguintes ambientes:
- MongoDB Atlas: The fully managed service for MongoDB deployments in the cloud
MongoDB Enterprise: a versão autogerenciada e baseada em assinatura do MongoDB
MongoDB Community: uma versão com código disponível, de uso gratuito e autogerenciada do MongoDB
Sintaxe
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 | necessidade | Descrição |
|---|---|---|
Obrigatório | Especifica a coleção estrangeira no mesmo banco de dados para ingressar na coleção local. É possível, em alguns casos extremos, substituir A partir do MongoDB 5.1, a coleção | |
Opcional se | Specifies the field from the documents input to the | |
Opcional se | Especifica o If a foreign document does not contain a | |
Opcional | Especifica variáveis para uso nos estágios do pipeline. Use as expressões variáveis para acessar os campos dos documentos da coleção local que são inseridos no To reference variables in pipeline stages, use the The let variables can be accessed by the stages in the pipeline, including additional
| |
Opcional se | Especifica o The The To reference variables in pipeline stages, use the The let variables can be accessed by the stages in the pipeline, including additional
| |
Obrigatório | Especifica o nome do novo campo de array a ser adicionado aos documentos de entrada. O novo campo de array contém os documentos correspondentes da coleção |
Correspondência de igualdade com uma única condição de junção
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> } }
Observação
Neste exemplo, pipeline é opcional e executado após o estágio de igualdade local e externa.
A operação corresponde a esta declaração pseudo-SQL:
SELECT *, ( SELECT ARRAY_AGG(*) FROM <collection to join> WHERE <foreignField> = <collection.localField> ) AS <output array field> FROM collection;
Observação
As declarações SQL nesta página estão incluídas para comparação com a sintaxe do pipeline de agregação do MongoDB. As declarações SQL não são executáveis.
Para exemplos do MongoDB, consulte estas páginas:
Condições de junção e subqueries em uma coleção estrangeira
MongoDB suporta:
Executando um pipeline em uma coleção estrangeira.
Várias condições de junções.
Subconsultas correlacionadas e não 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.
Observação
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.
As subconsultas correlacionadas do MongoDB são comparáveis às subconsultas correlacionadas do SQL, onde a consulta interna faz referência a valores de consulta externa. Uma subconsulta SQL não correlacionada não faz referência a valores de consulta externa.
O MongoDB 5.0 também suporta subqueries correlacionadas concisas.
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> } }
A operação corresponde a esta declaração 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> );
Veja os seguintes exemplos:
Subconsultas correlacionadas usando sintaxe concisa
Novidade na versão 5.0.
A partir do MongoDB 5.0, você pode usar uma sintaxe concisa para uma subquery correlacionada. As subqueries correlacionadas fazem referência a campos de documentos de uma coleção estrangeira e da coleção "local" na qual o método aggregate() foi executado.
A nova sintaxe concisa a seguir remove o requisito de uma correspondência de igualdade nos campos estrangeiros e local dentro de um 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> } }
A operação corresponde a esta declaração 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> );
Veja este exemplo:
Comportamento
Visualizações e agrupamento
If performing an aggregation that involves multiple views, such as with $lookup or $graphLookup, the views must have the same collation.
Restrições
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> } }
Suporte do Atlas Search
Starting in MongoDB 6.0, you can specify the Atlas Search $search or $searchMeta stage in the $lookup pipeline to search collections on the Atlas cluster. The $search or the $searchMeta stage must be the first stage inside the $lookup pipeline.
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:
[{ "$lookup": { "from": <foreign collection>, localField: <field from the input documents>, foreignField: <field from the documents of the "from" collection>, "as": <output array field>, "pipeline": [{ "$search": { "<operator>": { <operator-specification> } }, ... }] } }]
[{ "$lookup": { "from": <foreign collection>, localField: <field from the input documents>, foreignField: <field from the documents of the "from" collection>, "as": <output array field>, "pipeline": [{ "$searchMeta": { "<collector>": { <collector-specification> } }, ... }] } }]
To see an example of $lookup with $search, see the Atlas Search tutorial Run an Atlas Search $search Query Using $lookup.
Coleções fragmentadas
Starting in MongoDB 5.1, you can specify sharded collections in the from parameter of $lookup stages.
Você não pode usar a etapa $lookup dentro de uma transação enquanto segmenta uma coleção fragmentada.
Mecanismo de execução de consulta baseado em slot
Observação
A partir da versão 7.0.17, o mecanismo de execução de queries baseado em slots não está mais ativado por padrão para versões de patch do 7.0. Se você deseja que suas queries usem o mecanismo de execução de queries baseado em slots, atualize para a versão 8.0, onde está habilitado por padrão.
Starting in version 6.0, MongoDB can use the slot-based execution query engine to execute $lookup stages if all preceding stages in the pipeline can also be executed by the slot-based execution engine and none of the following conditions are true:
A operação
$lookupexecuta um pipeline em uma coleção estrangeira. Para ver um exemplo desse tipo de operação, consulte Condições de união e subqueries em uma coleção estrangeira.Os
localFieldouforeignFieldde$lookupespecificam componentes numéricos. Por exemplo:{ localField: "restaurant.0.review" }.O campo
fromde qualquer$lookupno pipeline especifica uma visualização ou coleção fragmentada.
Para mais informações, consulte Otimização do$lookup.
Considerações de desempenho
$lookup o desempenho depende do tipo de operação executada. Consulte a tabela a seguir para considerações de desempenho para diferentes operações do $lookup.
$lookup (operação) | Considerações de desempenho |
|---|---|
| |
| |
|
Para obter estratégias gerais de desempenho, consulte Estratégias de indexação e Otimização de consulta.
Exemplos
Os exemplos nesta página usam dados do conjunto de dados sample_mflix. Para obter detalhes sobre como carregar este conjunto de dados em sua implantação do MongoDB autogerenciado, consulte Carregar o conjunto de dados de amostra. Se você fez alguma modificação nos bancos de dados de amostra, talvez seja necessário descartar e recriar os bancos de dados para executar os exemplos nesta página.
Realizar uma única junção de igualdade com $lookup
A operação de agregação a seguir primeiro filtra a coleção movies para filmes com runtime maior que 1000 e, em seguida, une-se à coleção comments nos campos _id e 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: [] } ]
A operação corresponde a esta declaração pseudo-SQL:
SELECT *, movie_comments FROM movies WHERE movie_comments IN ( SELECT * FROM comments WHERE movie_id = movies._id );
Para obter mais informações, consulte Considerações sobre o desempenho da correspondência de igualdade.
Use $lookup com uma array
Se localField for uma array, você poderá fazer a correspondência dos elementos de array com um escalar foreignField sem um estágio $unwind.
A seguinte operação de agregação une a coleção movies à coleção users, fazendo a correspondência do campo de array cast de movies com o 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' } ] } ]
Usar $lookup com $mergeObjects
O operador $mergeObjects combina vários documentos em um ú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 } ]
Use várias condições de junção e uma subquery correlacionada
Os pipelines podem ser executados em uma coleção estrangeira e incluir diversas condições de junção. O operador $expr permite condições de junção mais complexas, incluindo conjunções e correspondências de não igualdade.
Uma condição de junção pode fazer referência a um campo na coleção local na qual o método aggregate() foi executado e fazer referência a um campo na coleção estrangeira. Isso permite uma subquery correlacionada entre as duas coleções.
O MongoDB 5.0 também aceita subqueries correlacionadas concisas.
O seguinte exemplo:
Une as coleções
moviesecommentsusando os campos_idemovie_id.Filtra os comentários para incluir apenas os postados após o ano de lançamento do filme.
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: [] } ]
A operação corresponde a esta declaração 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:
Os índices só podem ser usados para comparações entre campos e constantes, portanto, o operando
letdeve ser resolvido para uma constante.Por exemplo, uma comparação entre
$ae um valor constante pode usar um índice, mas uma comparação entre$ae$bnão pode.Os índices não são usados para comparações onde o operando
letresolve para um valor vazio ou ausente.Índices multichave, parciais ou esparsos não são usados.
Por exemplo, se o índice { movie_id: 1 } existir na coleção comments:
- A correspondência de igualdade no campo
comments.movie_idutiliza o índice.
Execute uma subconsulta não correlacionada $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.
Observação
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.
A operação a seguir une a coleção users a filmes que têm um tempo de execução maior que 1000 minutos da coleção 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 } ] } ]
A operação corresponde a esta declaração pseudo-SQL:
SELECT *, long_movies FROM users WHERE long_movies IN ( SELECT title, year FROM movies WHERE runtime > 1000 );
For more information, see Uncorrelated Subquery Performance Considerations.
Execute uma subconsulta concisa correlacionada com $lookup
Novidade na versão 5.0.
Starting in MongoDB 5.0, an aggregation pipeline $lookup stage supports a concise correlated subquery syntax that improves joins between collections. The new concise syntax removes the requirement for an equality match on the foreign and local fields inside of an $expr operator in a $match stage.
O seguinte exemplo:
Joins the
moviesandcommentscollections by matching the localField_idwith the foreignFieldmovie_id. The match is performed before thepipelineis run.Filtra os comentários para incluir apenas os postados após o ano de lançamento do filme, acessado usando
$$movie_yeare$date, respectivamente.
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 exemplo usa a sintaxe detalhada mais antiga das versões do MongoDB anteriores à 5.0 e retorna os mesmos resultados do exemplo 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') } ] } ]
Os exemplos anteriores correspondem a esta declaração 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 );
For more information, see Correlated Subquery Performance Considerations.
Os exemplos de C# nesta página utilizam o banco de dados sample_mflix a partir dos conjuntos de dados de amostra do Atlas. Para saber como criar um cluster MongoDB Atlas gratuito e carregar os conjuntos de dados de exemplo, consulte Introdução na documentação do driver MongoDB .NET/C#.
A seguinte classe Movie modela os documentos na collection 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; } }
A seguinte classe Comment modela os documentos na collection sample_mflix.comments:
[] public class Comment { [] public ObjectId Id { get; set; } [] public ObjectId MovieId { get; set; } [] public string Text { get; set; } = null!; }
A seguinte classe LookupResult armazena a saída do estágio $lookup:
[] public class LookupResult { [] public ObjectId Id { get; set; } [] public string Title { get; set; } = null!; public List<Comment> Comments { get; set; } = []; }
Para usar o driver MongoDB .NET/C# para adicionar um estágio $lookup a uma agregação pipeline, chame o método UnionWith() em um objeto PipelineDefinition.
O exemplo abaixo cria um estágio de pipeline que executa uma junção externa esquerda entre as collections movies e comments. O código une o campo Id de cada documento Movie ao campo MovieId nos documentos Comment. Os comentários de cada filme são armazenados em um campo chamado Comments em 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);
Os exemplos do Node.js nesta página utilizam o banco de dados do sample_mflix a partir dos conjuntos de dados de amostra do Atlas. Para saber como criar um cluster gratuito do MongoDB Atlas e carregar os conjuntos de dados de exemplo, consulte Introdução na documentação do driver do MongoDB Node.js
Para usar o driver Node.js do MongoDB para adicionar um estágio $lookup a um pipeline de agregação , use o operador $lookup em um objeto de pipeline.
O exemplo a seguir cria um estágio de pipeline que executa uma junção externa esquerda entre as coleções movies e comments. O código conecta o campo _id de cada documento movie ao campo movie_id nos documentos comment. O campo comments armazena os comentários de cada filme em cada documento movie. O exemplo em seguida executa o pipeline de agregação:
const pipeline = [ { $lookup: { from: "comments", localField: "_id", foreignField: "movie_id", as: "comments" } } ]; const cursor = collection.aggregate(pipeline); return cursor;