MongoDB
 sql >> Database >  >> NoSQL >> MongoDB

Posso usare popola prima di aggregare in mangusta?

No, non puoi chiamare .populate() prima di .aggregate() , e c'è un'ottima ragione per cui non puoi. Ma ci sono diversi approcci che puoi adottare.

Il .populate() il metodo funziona "lato client" in cui il codice sottostante esegue effettivamente query aggiuntive (o più precisamente un $in query ) per "cercare" gli elementi specificati dalla raccolta di riferimento.

Al contrario .aggregate() è un'operazione "lato server", quindi in pratica non è possibile manipolare il contenuto "lato client" e quindi avere quei dati disponibili per le fasi della pipeline di aggregazione in un secondo momento. Tutto deve essere presente nella collezione su cui stai operando.

Un approccio migliore qui è disponibile con MongoDB 3.2 e versioni successive, tramite $lookup operazione di pipeline di aggregazione. Probabilmente è anche meglio gestire dall'User raccolta in questo caso per restringere la selezione:

User.aggregate(
    [
        // Filter first
        { "$match": {
            "age": { "$gt": 20 } 
        }},
        // Then join
        { "$lookup": {
            "from": "scores",
            "localField": "userID",
            "foriegnField": "userID",
            "as": "score"
        }},
        // More stages
    ],
    function(err,results) {

    }
)

Questo fondamentalmente includerà un nuovo campo "punteggio" all'interno di User oggetto come una "matrice" di elementi che corrispondevano in "ricerca" all'altra raccolta:

{
    "userID": "abc",
    "age": 21,
    "score": [{
        "userID": "abc",
        "score": 42,
        // other fields
    }]
}

Il risultato è sempre un array, poiché l'utilizzo generale previsto è un "unione a sinistra" di una possibile relazione "uno a molti". Se nessun risultato corrisponde, è solo un array vuoto.

Per utilizzare il contenuto, è sufficiente lavorare con un array in qualsiasi modo. Ad esempio, puoi utilizzare $arrayElemAt operatore per ottenere solo il primo elemento singolo dell'array in qualsiasi operazione futura. E quindi puoi semplicemente utilizzare il contenuto come qualsiasi normale campo incorporato:

        { "$project": {
            "userID": 1,
            "age": 1,
            "score": { "$arrayElemAt": [ "$score", 0 ] }
        }}

Se non hai MongoDB 3.2 disponibile, l'altra opzione per elaborare una query limitata dalle relazioni di un'altra raccolta è ottenere prima i risultati da quella raccolta e quindi utilizzare $in per filtrare sul secondo:

// 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) {

        }
    );

});

Quindi, ottenere l'elenco di utenti validi dall'altra raccolta al client e quindi inviarlo all'altra raccolta in una query è l'unico modo per farlo accadere nelle versioni precedenti.