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.