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

Posso usar preencher antes de agregar no mangusto?


Não, você não pode chamar .populate() antes de .aggregate() , e há uma boa razão pela qual você não pode. Mas existem diferentes abordagens que você pode tomar.

O .populate() O método funciona "lado do cliente" onde o código subjacente realmente executa consultas adicionais (ou mais precisamente um $in query ) para "pesquisar" o(s) elemento(s) especificado(s) da coleção referenciada.

Em contraste .aggregate() é uma operação do "lado do servidor", portanto, você basicamente não pode manipular o conteúdo do "lado do cliente" e, em seguida, ter esses dados disponíveis para os estágios do pipeline de agregação posteriormente. Tudo precisa estar presente na coleção em que você está operando.

Uma abordagem melhor aqui está disponível com o MongoDB 3.2 e posterior, por meio do $lookup operação de pipeline de agregação. Provavelmente também é melhor lidar com o User coleção neste caso, a fim de restringir a seleção:
User.aggregate(
    [
        // Filter first
        { "$match": {
            "age": { "$gt": 20 } 
        }},
        // Then join
        { "$lookup": {
            "from": "scores",
            "localField": "userID",
            "foriegnField": "userID",
            "as": "score"
        }},
        // More stages
    ],
    function(err,results) {

    }
)

Isso basicamente incluirá um novo campo "score" dentro do User object como um "array" de itens que corresponderam em "lookup" à outra coleção:
{
    "userID": "abc",
    "age": 21,
    "score": [{
        "userID": "abc",
        "score": 42,
        // other fields
    }]
}

O resultado é sempre uma matriz, pois o uso geral esperado é uma "junção à esquerda" de um possível relacionamento "um para muitos". Se nenhum resultado for correspondido, então é apenas uma matriz vazia.

Para usar o conteúdo, basta trabalhar com um array de qualquer maneira. Por exemplo, você pode usar o $arrayElemAt operador para obter apenas o primeiro elemento da matriz em quaisquer operações futuras. E então você pode simplesmente usar o conteúdo como qualquer campo incorporado normal:
        { "$project": {
            "userID": 1,
            "age": 1,
            "score": { "$arrayElemAt": [ "$score", 0 ] }
        }}

Se você não tiver o MongoDB 3.2 disponível, sua outra opção para processar uma consulta limitada pelas relações de outra coleção é primeiro obter os resultados dessa coleção e usar $in para filtrar no segundo:
// Match the user collection
User.find({ "age": { "$gt": 20 } },function(err,users) {

    // Get id list      
    userList = users.map(function(user) {
       return user.userID;
    });

    Score.aggregate(
        [ 
            // use the id list to select items
            { "$match": {
                "userId": { "$in": userList }
            }},
            // more stages
        ],
        function(err,results) {

        }
    );

});

Portanto, obter a lista de usuários válidos da outra coleção para o cliente e, em seguida, alimentar a outra coleção em uma consulta é a única maneira de fazer isso acontecer em versões anteriores.