MongoDB
 sql >> Base de Dados >  >> NoSQL >> MongoDB

$ lookup em ObjectIds em uma matriz

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.