Menu Docs
Página inicial do Docs
/
Manual do MongoDB
/ / /

$lookup (agregação)

Nesta página

  • Definição
  • Compatibilidade
  • Sintaxe
  • Correspondência de igualdade com uma única condição de junção
  • Condições de junção e subconsultas em uma coleção associada
  • Subconsultas correlacionadas usando sintaxe concisa
  • Comportamento
  • Visualizações e agrupamento
  • Restrições
  • Suporte do Atlas Search
  • Coleções fragmentadas
  • Mecanismo de execução de consulta baseado em slot
  • Considerações de desempenho
  • Exemplos
  • Realizar uma única junção de igualdade com $lookup
  • Use $lookup com uma array
  • Use $lookup com $mergeObjects
  • Use várias condições de junção e uma subquery correlacionada
  • Execute uma subconsulta não correlacionada $lookup
  • Execute uma subconsulta concisa correlacionada com $lookup
  • Namespaces em Subpipelines
$lookup

Alterado na versão 8.0.

Realiza uma união externa esquerda em uma coleção no mesmo banco de dados para filtrar documentos da coleção "unida" para processamento. O estágio $lookup adiciona um novo campo de matriz para cada documento de entrada. O novo campo de array contém os documentos correspondentes da coleção "unida". O estágio $lookup passa esses documentos remodelados para o próximo estágio.

A partir do MongoDB 5.1, é possível usar $lookup com coleções fragmentadas.

Para combinar elementos de duas coleções diferentes, use o estágio de pipeline $unionWith.

Você pode utilizar o $lookup para implantações hospedadas nos seguintes ambientes:

  • MongoDB Atlas: o serviço totalmente gerenciado para implantações do MongoDB na nuvem

  • 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

O estágio $lookup tem as variações de sintaxe mostradas nas seções a seguir.

Para realizar uma correspondência de igualdade entre um campo dos documentos de entrada com um campo dos documentos da coleção "associada", o estágio $lookup possui esta sintaxe:

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

O $lookup pega um documento com estes campos:

Campo
Descrição

Especifica a coleção no mesmo banco de dados com a qual realizar a junção.

from é opcional. Em vez disso, você pode usar um estágio $documents em um estágio $lookup. Por ver um exemplo, consulte Usar um estágio $documents em um estágio $lookup.

A partir do MongoDB 5.1, a coleção especificada no parâmetro from pode ser fragmentada.

Especifica o campo da entrada de documentos para o estágio $lookup. $lookup realiza uma correspondência de igualdade entre localField e foreignField dos documentos da coleção from. Se um documento de entrada não contém o localField, o $lookup trata o campo como tendo um valor de null para fins de correspondência.

Especifica o campo dos documentos na coleção from. $lookup realiza uma correspondência de igualdade entre foreignField e localField dos documentos de entrada. Se um documento na coleção from não contém o foreignField, o $lookup trata o valor como null para fins de correspondência.

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 from. Se o nome especificado já existir no documento de entrada, o campo existente será substituído.

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:

MongoDB suporta:

  • Execução de pipeline em uma coleção associada.

  • Várias condições de junções.

  • Subconsultas correlacionadas e não correlacionadas.

No MongoDB, uma sub-query correlacionada é um pipeline em um estágio $lookup que faz referência a campos de documentos de uma coleção associada. Uma subquery não correlacionada não faz referência a campos associados.

Observação

A partir do MongoDB 5.0, para uma sub-query não correlacionada em um estágio de pipeline $lookup que contém um estágio $sample, o operador $sampleRate ou o operador $rand, a sub-query é sempre executada novamente se for repetida. Anteriormente, dependendo do tamanho da saída da sub-query, o resultado da sub-query era armazenado em cache ou a sub-query era executada novamente.

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.

Para executar subconsultas correlacionadas e não correlacionadas com duas coleções e executar outras condições de junção além de uma única correspondência de igualdade, use esta sintaxe $lookup:

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

O estágio $lookup aceita um documento com estes campos:

Campo
Descrição

Especifica a coleção no mesmo banco de dados para executar a operação de junção.

from é opcional. Em vez disso, você pode usar um estágio $documents em um estágio $lookup. Por ver um exemplo, consulte Usar um estágio $documents em um estágio $lookup.

A partir do MongoDB 5.1, a coleção from pode ser fragmentada.

Opcional. Especifica variáveis a serem usadas nos estágios de pipeline. Use as expressões variáveis para acessar os campos dos documentos da coleção associada que são inseridos no pipeline.

Para fazer referência a variáveis nos estágios do pipeline, use a sintaxe "$$<variable>".

As variáveis let podem ser acessadas pelos estágios no pipeline, incluindo estágios $lookup adicionais aninhados no pipeline.

  • Um estágio $match exige o uso de um operador $expr para acessar as variáveis. O operador $expr permite o uso de expressões de agregação dentro da sintaxe $match.

    Os operadores de comparação $eq, $lt, $lte, $gt e $gte colocados em um operador $expr podem utilizar um índice na coleção from referenciada em um estágio $lookup. Limitações:

    • Os índices só podem ser usados para comparações entre campos e constantes, portanto, o operando let deve ser resolvido para uma constante.

      Por exemplo, uma comparação entre $a e um valor constante pode usar um índice, mas uma comparação entre $a e $b não pode.

    • Os índices não são usados para comparações onde o operando let resolve para um valor vazio ou ausente.

    • Índices multichave não são usados.

  • Outros estágios (não$match) no pipeline não exigem um operador $expr para acessar as variáveis.

Especifica o pipeline a ser executado na coleção associada. O pipeline determina os documentos resultantes da coleção associada. Para retornar todos os documentos, especifique um campo pipeline [] vazio.

O pipeline não pode incluir o estágio $out nem o $merge. A partir de v6.0, o pipeline pode conter o estágio $search do Atlas Search como o primeiro dentro do pipeline. Para saber mais, consulte Suporte do Atlas Search.

O pipeline não pode acessar diretamente os campos do documento associado. Em vez disso, defina variáveis para os campos do documento associado usando a opção let e, em seguida, faça referência às variáveis nos estágios pipeline.

Para fazer referência a variáveis nos estágios do pipeline, use a sintaxe "$$<variable>".

As variáveis let podem ser acessadas pelos estágios no pipeline, incluindo estágios $lookup adicionais aninhados no pipeline.

  • Um estágio $match exige o uso de um operador $expr para acessar as variáveis. O operador $expr permite o uso de expressões de agregação dentro da sintaxe $match.

    Os operadores de comparação $eq, $lt, $lte, $gt e $gte colocados em um operador $expr podem utilizar um índice na coleção from referenciada em um estágio $lookup. Limitações:

    • Os índices só podem ser usados para comparações entre campos e constantes, portanto, o operando let deve ser resolvido para uma constante.

      Por exemplo, uma comparação entre $a e um valor constante pode usar um índice, mas uma comparação entre $a e $b não pode.

    • Os índices não são usados para comparações onde o operando let resolve para um valor vazio ou ausente.

    • Índices multichave não são usados.

  • Outros estágios (não$match) no pipeline não exigem um operador $expr para acessar as variáveis.

Especifica o nome do novo campo de array a ser adicionado aos documentos associados. O novo campo de array contém os documentos correspondentes da coleção associada. Se o nome especificado já existir no documento associado, o campo existente será substituído.

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:

Novidades na versão 5.0.

A partir do MongoDB 5.0, você pode usar uma sintaxe concisa para uma subconsulta correlacionada. As subconsultas correlacionadas fazem referência a campos de documentos de uma coleção "estrangeira" associada 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>
}
}

O $lookup aceita um documento com estes campos:

Campo
Descrição

Especifica a coleção estrangeira no mesmo banco de dados para ingressar na coleção local.

from é opcional. Em vez disso, você pode usar um estágio $documents em um estágio $lookup. Por ver um exemplo, consulte Usar um estágio $documents em um estágio $lookup.

A partir do MongoDB 5.1, a coleção from pode ser fragmentada.

Especifica o localField dos documentos locais para realizar uma correspondência de igualdade com o foreignField dos documentos estrangeiros.

Se um documento local não contiver um valor localField, o $lookup usará um valor null para a correspondência.

Especifica o foreignField dos documentos estrangeiros para realizar uma correspondência de igualdade com os documentos locais localField.

Se um documento estrangeiro não contiver um valor foreignField, o $lookup usará um valor null para a correspondência.

Opcional. Especifica as variáveis a serem usadas nos estágios do pipeline . Use as expressões variáveis para acessar os campos do documento que são inseridos no pipeline.

Para fazer referência a variáveis nos estágios do pipeline, use a sintaxe "$$<variable>".

As variáveis let podem ser acessadas pelos estágios no pipeline, incluindo estágios $lookup adicionais aninhados no pipeline.

  • Um estágio $match exige o uso de um operador $expr para acessar as variáveis. O operador $expr permite o uso de expressões de agregação dentro da sintaxe $match.

    Os operadores de comparação $eq, $lt, $lte, $gt e $gte colocados em um operador $expr podem utilizar um índice na coleção from referenciada em um estágio $lookup. Limitações:

    • Os índices só podem ser usados para comparações entre campos e constantes, portanto, o operando let deve ser resolvido para uma constante.

      Por exemplo, uma comparação entre $a e um valor constante pode usar um índice, mas uma comparação entre $a e $b não pode.

    • Os índices não são usados para comparações onde o operando let resolve para um valor vazio ou ausente.

    • Índices multichave não são usados.

  • Outros estágios (não$match) no pipeline não exigem um operador $expr para acessar as variáveis.

Especifica o pipeline a ser executado na coleção estrangeira. O pipeline retorna documentos da coleção estrangeira. Para retornar todos os documentos, especifique um campo pipeline [] vazio.

O pipeline não pode incluir os estágios $out ou $merge . A partir dev6.0, o pipeline pode conter o estágio Atlas Search $search como o primeiro estágio dentro do pipeline. Para saber mais, consulte Compatibilidade do Atlas Search.

O pipeline não pode acessar diretamente os campos do documento. Como alternativa, defina variáveis para os campos do documento usando a opção let e, em seguida, faça referência às variáveis nos estágios pipeline.

Para fazer referência a variáveis nos estágios do pipeline, use a sintaxe "$$<variable>".

As variáveis let podem ser acessadas pelos estágios no pipeline, incluindo estágios $lookup adicionais aninhados no pipeline.

  • Um estágio $match exige o uso de um operador $expr para acessar as variáveis. O operador $expr permite o uso de expressões de agregação dentro da sintaxe $match.

    Os operadores de comparação $eq, $lt, $lte, $gt e $gte colocados em um operador $expr podem utilizar um índice na coleção from referenciada em um estágio $lookup. Limitações:

    • Os índices só podem ser usados para comparações entre campos e constantes, portanto, o operando let deve ser resolvido para uma constante.

      Por exemplo, uma comparação entre $a e um valor constante pode usar um índice, mas uma comparação entre $a e $b não pode.

    • Os índices não são usados para comparações onde o operando let resolve para um valor vazio ou ausente.

    • Índices multichave não são usados.

  • Outros estágios (não$match) no pipeline não exigem um operador $expr para acessar as variáveis.

Especifica o nome do novo campo de array a ser adicionado aos documentos estrangeiros. O novo campo de array contém os documentos correspondentes da coleção estrangeira. Se o nome especificado já existir no documento estrangeiro, o campo existente será substituído.

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:

Se executar uma agregação que envolva múltiplas visualizações, como com $lookup ou $graphLookup, as visualizações deverão ter o mesmo agrupamento.

Você não pode incluir os estágios $out ou $merge no estágio $lookup. Ou seja, ao especificar um pipeline para a coleção associada, você não pode incluir nenhum dos estágios no 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>
}
}

A partir do MongoDB 6.0, você pode especificar o $search do Atlas Search ou o estágio do $searchMeta no pipeline de $lookup para pesquisar coleções no cluster do Atlas. O estágio $search ou $searchMeta deve ser o primeiro dentro do pipeline $lookup.

Por exemplo, ao realizar Condições de junção e subconsultas em uma coleção associada ou executar Subconsultas correlacionadas usando sintaxe concisa, você pode especificar $search ou $searchMeta dentro do pipeline, conforme mostrado abaixo:

[{
"$lookup": {
"from": <joined 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": <joined 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>
}
},
...
}]
}
}]

Para ver um exemplo de $lookup com $search, consulte o tutorial Executar uma query $search do Atlas Search usando $lookup, do Atlas Search.

A partir do MongoDB 5.1, você pode especificar coleções fragmentadas no parâmetro from de $lookup estágios.

A partir do MongoDB 8.0, você pode usar o estágio $lookup em uma transação enquanto visa uma coleção fragmentada.

A partir da versão 6.0, o MongoDB pode usar o mecanismo de execução de query baseado em slots para executar $lookup estágios se todos os estágios anteriores no pipeline também puderem ser executados pelo mecanismo de execução baseado em slots e nenhuma das seguintes condições for verdadeira:

  • A operação $lookup executa um pipeline em uma coleção unida. Para ver um exemplo desse tipo de operação, consulte Condições de união e subqueries em uma coleção.

  • Os localField ou foreignField de $lookup especificam componentes numéricos. Por exemplo: { localField: "restaurant.0.review" }.

  • O campo from de qualquer $lookup no pipeline especifica uma visualização ou coleção fragmentada.

Para mais informações, consulte Otimização do$lookup.

$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
  • $lookup As operações que executam correspondências de igualdade com uma única união executam melhor quando a coleção externa contém um índice no foreignField.

    <strong class=\"\">IMPORTANTE: Se um índice de suporte no foreignField não existir, uma $lookup operação que executa uma correspondência de igualdade com uma única junção provavelmente terá um desempenho ruim.

  • $lookup operações que contêm subqueries não correlacionadas têm um desempenho melhor se o pipeline interno conseguir referenciar um índice da coleção externa.

  • O MongoDB só precisa executar a subconsulta $lookup uma vez antes de armazenar a consulta em cache porque não há relacionamento entre a origem e as coleções externas. A subconsulta não é baseada em nenhum valor na coleção de origem. Este comportamento melhora o desempenho para execuções subsequentes da operação $lookup.

  • $lookup operações que contêm subqueries correlacionadas têm um desempenho melhor se as seguintes condições se aplicam:

    • A coleção estrangeira contém um índice no foreignField.

    • A coleção estrangeira contém um índice que faz referência ao pipeline interno.

  • Se o pipeline passar um grande número de documentos para a consulta $lookup, as estratégias a seguir poderão melhorar o desempenho:

    • Reduz o número de documentos que o MongoDB passa para a consulta do $lookup. Por exemplo, defina um filtro mais rigoroso durante o estágio $match.

    • Execute o pipeline interno da subquery $lookup como query separada e use $out para criar uma coleção temporária. Em seguida, execute uma correspondência de igualdade com uma única união.

    • Reconsidere o esquema dos dados para garantir que seja ideal para o caso de uso.

Para obter estratégias gerais de desempenho, consulte Estratégias de indexação e Otimização de consulta.

Importante

O uso excessivo de $lookup em uma consulta pode diminuir o desempenho. Para evitar vários estágios $lookup, adote um modelo de dados embutido para melhorar o desempenho da consulta.

Crie uma coleção orders com estes documentos:

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

Crie outra coleção inventory com estes 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 }
] )

A operação de agregação a seguir na coleção orders une os documentos de orders com os documentos da coleção inventory usando os campos item da coleção orders e o campo sku da coleção inventory:

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

A operação retorna estes 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 }
]
}

A operação corresponde a esta declaração pseudo-SQL:

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

Para obter mais informações, consulte Considerações sobre o desempenho da correspondência de igualdade.

Se localField for uma array, você poderá fazer a correspondência dos elementos de array com um escalar foreignField sem um estágio $unwind.

Por exemplo, crie uma coleção de exemplo classes com estes 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"] }
] )

Crie outra coleção members com estes 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" }
] )

A seguinte operação de agregação une documentos na coleção classes com a coleção members, correspondendo o campo enrollmentlist ao campo name:

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

A operação retorna o seguinte:

{
"_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" }
]
}

O operador $mergeObjects combina vários documentos em um único documento.

Crie uma coleção orders com estes documentos:

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

Crie outra coleção items com estes 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 }
] )

A operação a seguir usa primeiro o estágio $lookup para unir as duas coleções pelos campos item e, em seguida, usa $mergeObjects no $replaceRoot para mesclar os documentos unidos de items e 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 } }
] )

A operação retorna estes 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
}

Os pipelines podem ser executados em uma coleção associada 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 associada. Isso permite uma subconsulta correlacionada entre as duas coleções.

O MongoDB 5.0 é compatível com subconsultas correlacionadas concisas.

Crie uma coleção orders com estes 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 }
] )

Crie outra coleção warehouses com estes 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 }
] )

O seguinte exemplo:

  • Usa uma subconsulta correlacionada com uma junção nos campos orders.item e warehouse.stock_item.

  • Garante que a quantidade do item em estoque possa atender à quantidade solicitada.

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"
}
}
] )

A operação retorna estes 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 } ]
}

A operação corresponde a esta declaração pseudo-SQL:

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

Os operadores de comparação $eq, $lt, $lte, $gt e $gte colocados em um operador $expr podem utilizar um índice na coleção from referenciada em um estágio $lookup. Limitações:

  • Os índices só podem ser usados para comparações entre campos e constantes, portanto, o operando let deve ser resolvido para uma constante.

    Por exemplo, uma comparação entre $a e um valor constante pode usar um índice, mas uma comparação entre $a e $b não pode.

  • Os índices não são usados para comparações onde o operando let resolve para um valor vazio ou ausente.

  • Índices multichave não são usados.

Por exemplo, se o índice { stock_item: 1, instock: 1 } existir na coleção warehouses:

  • A correspondência de igualdade no campo warehouses.stock_item utiliza o índice.

  • A parte da faixa da consulta no campo warehouses.instock também utiliza o campo indexado no índice composto.

Dica

Veja também:

Um estágio $lookup do pipeline de agregação pode executar um pipeline na coleção associada, o que permite subqueries não correlacionadas. Uma subquery não correlacionada não faz referência aos campos do documento associado.

Observação

A partir do MongoDB 5.0, para uma sub-query não correlacionada em um estágio de pipeline $lookup que contém um estágio $sample, o operador $sampleRate ou o operador $rand, a sub-query é sempre executada novamente se for repetida. Anteriormente, dependendo do tamanho da saída da sub-query, o resultado da sub-query era armazenado em cache ou a sub-query era executada novamente.

Crie uma coleção absences com estes 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") ] },
] )

Crie outra coleção holidays com estes 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") }
] )

A operação a seguir une a coleção absences às informações de feriados de 2018 da coleção holidays:

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

A operação retorna o seguinte:

{
_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")
}
]
}

A operação corresponde a esta declaração pseudo-SQL:

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

Para obter mais informações, consulte Considerações sobre desempenho de subconsultas não correlacionadas.

Novidades na versão 5.0.

A partir do MongoDB 5.0, um estágio $lookup do pipeline de agregação suporta uma sintaxe de sub-query correlacionada concisa que melhora as uniões entre coleções. A nova sintaxe concisa remove a exigência de uma correspondência de igualdade nos campos externo e local dentro de um operador $expr em um estágio $match.

Criar uma coleção 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" ]
}
] )

Crie outra coleção orders com pedidos de comidas e bebidas opcionais:

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"
}
] )

O seguinte exemplo:

  • Associa as coleções orders e restaurants combinando o orders.restaurant_name localField com o restaurants.name foreignField. A correspondência é executada antes de pipeline ser executado.

  • Realiza uma correspondência de array $in entre os campos orders.drink e restaurants.beverages que são acessados usando $$orders_drink e $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"
}
}
] )

Há uma correspondência para o valor soda nos campos orders.drink e restaurants.beverages. Esta saída mostra a array matches e contém todos os campos associados da coleção restaurants para a correspondência:

{
"_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 da introdução de subqueries correlacionadas concisas, era necessário usar uma correspondência de igualdade $eq entre o campo local e o campo unido no operador $expr no estágio do pipeline $lookup conforme mostrado em Usar condições de união múltiplas e uma subquery correlacionada.

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.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"
}
}
] )

Os exemplos anteriores correspondem a esta declaração pseudo-SQL:

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

Para mais informações, consulte Considerações sobre o desempenho de subconsultas correlacionadas.

A partir do MongoDB 8.0, os namespaces em subpipelines dentro $lookup e $unionWith são validados para garantir o uso correto dos campos from e coll:

  • Por $lookup, omita o campo from se você usar um subpipeline com um estágio que não exija uma coleção especificada. Por exemplo, um estágio $documents.

  • Da mesma forma, para $unionWith, omita o campo coll.

Comportamento inalterado:

  • Para um $lookup que começa com um estágio para uma coleção, por exemplo, um subpipeline $match ou $collStats, você deve incluir o campo from e especificar a coleção.

  • Da mesma forma, para $unionWith, inclua o campo coll e especifique a coleção.

O cenário a seguir mostra um exemplo.

Criar uma coleção cakeFlavors:

db.cakeFlavors.insertMany( [
{ _id: 1, flavor: "chocolate" },
{ _id: 2, flavor: "strawberry" },
{ _id: 3, flavor: "cherry" }
] )

A partir do MongoDB 8.0, o exemplo a seguir retorna um erro porque contém um campo from inválido :

db.cakeFlavors.aggregate( [ {
$lookup: {
from: "cakeFlavors",
pipeline: [ { $documents: [ {} ] } ],
as: "test"
}
} ] )

Nas versões do MongoDB anteriores a 8.0, o exemplo anterior é executado.

Para obter um exemplo com um campo from válido , consulte Executar uma única junção de igualdade com $lookup.

Voltar

$listSessions