Atualização de 2017
$lookup agora pode usar diretamente um array como o campo local.
$unwind
não é mais necessário. Resposta antiga
A
$lookup
estágio de pipeline de agregação não funcionará diretamente com uma matriz. A principal intenção do design é uma "junção à esquerda" como um tipo de junção "um para muitos" (ou realmente uma "pesquisa") nos possíveis dados relacionados. Mas o valor deve ser singular e não uma matriz. Portanto, você deve "desnormalizar" o conteúdo primeiro antes de executar o
$lookup
operação para que isso funcione. E isso significa usar $unwind
:db.orders.aggregate([
// Unwind the source
{ "$unwind": "$products" },
// Do the lookup matching
{ "$lookup": {
"from": "products",
"localField": "products",
"foreignField": "_id",
"as": "productObjects"
}},
// Unwind the result arrays ( likely one or none )
{ "$unwind": "$productObjects" },
// Group back to arrays
{ "$group": {
"_id": "$_id",
"products": { "$push": "$products" },
"productObjects": { "$push": "$productObjects" }
}}
])
Após
$lookup
corresponde a cada membro do array o resultado é um array em si, então você $unwind
novamente e $group
para $push
novas matrizes para o resultado final. Observe que qualquer correspondência "left join" que não for encontrada criará uma matriz vazia para o "productObjects" no produto fornecido e, portanto, negará o documento para o elemento "product" quando o segundo
$unwind
é chamado. Embora um aplicativo direto para uma matriz seja bom, é assim que isso funciona atualmente, combinando um valor singular com um número possível.
Como
$lookup
é basicamente muito novo, atualmente funciona como seria familiar para aqueles que estão familiarizados com o mangusto como uma "versão de homem pobre" do .populate()
método oferecido lá. A diferença é que $lookup
oferece o processamento "do lado do servidor" do "join" em oposição ao do cliente e que parte da "maturidade" em $lookup
está faltando no que .populate()
oferece (como interpolar a pesquisa diretamente em uma matriz). Este é realmente um problema atribuído para melhoria SERVER-22881, portanto, com alguma sorte, isso atingiria o próximo lançamento ou um logo depois.
Como princípio de design, sua estrutura atual não é boa nem ruim, mas apenas sujeita a despesas gerais ao criar qualquer "junção". Como tal, o princípio básico do MongoDB no início se aplica, onde se você "pode" viver com os dados "pré-juntados" em uma coleção, então é melhor fazê-lo.
A outra coisa que pode ser dita de
$lookup
como princípio geral, é que a intenção da "junção" aqui é trabalhar ao contrário do que é mostrado aqui. Portanto, em vez de manter os "ids relacionados" dos outros documentos no documento "pai", o princípio geral que funciona melhor é quando os "documentos relacionados" contêm uma referência ao "pai". Então
$lookup
pode-se dizer que "funciona melhor" com um "design de relação" que é o inverso de algo como mangusto .populate()
executa suas junções do lado do cliente. Ao identificar o "um" dentro de cada "muitos", basta puxar os itens relacionados sem precisar $unwind
a matriz primeiro.