MongoDB
 sql >> Datenbank >  >> NoSQL >> MongoDB

Kann ich in Mongoose vor dem Aggregat auffüllen?

Nein, Sie können .populate() nicht aufrufen vor .aggregate() , und es gibt einen sehr guten Grund, warum Sie das nicht können. Aber es gibt verschiedene Ansätze, die Sie verfolgen können.

Die .populate() -Methode funktioniert "clientseitig", wo der zugrunde liegende Code tatsächlich zusätzliche Abfragen durchführt (oder genauer gesagt ein $in query ), um das/die angegebene(n) Element(e) aus der referenzierten Sammlung zu "suchen".

Im Gegensatz dazu .aggregate() ist ein "serverseitiger" Vorgang, sodass Sie Inhalte grundsätzlich nicht "clientseitig" manipulieren und diese Daten dann später den Phasen der Aggregationspipeline zur Verfügung stellen können. Es muss alles in der Sammlung vorhanden sein, die Sie bearbeiten.

Ein besserer Ansatz ist hier mit MongoDB 3.2 und höher über den Code $nachschlagen Aggregations-Pipeline-Betrieb. Auch wahrscheinlich am besten vom Benutzer zu handhaben Sammlung in diesem Fall, um die Auswahl einzugrenzen:

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

    }
)

Dies wird im Grunde genommen ein neues Feld "Score" innerhalb des User enthalten Objekt als ein "Array" von Elementen, die beim "Lookup" mit der anderen Sammlung übereinstimmten:

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

Das Ergebnis ist immer ein Array, da die allgemein erwartete Verwendung ein "Links-Join" einer möglichen "Eins-zu-Viele"-Beziehung ist. Wenn kein Ergebnis gefunden wird, ist es nur ein leeres Array.

Um den Inhalt zu verwenden, arbeiten Sie einfach in irgendeiner Weise mit einem Array. Beispielsweise können Sie $arrayElemAt verwenden Operator, um bei zukünftigen Operationen nur das einzelne erste Element des Arrays zu erhalten. Und dann können Sie den Inhalt einfach wie jedes normale eingebettete Feld verwenden:

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

Wenn Sie MongoDB 3.2 nicht zur Verfügung haben, besteht Ihre andere Möglichkeit, eine durch die Beziehungen einer anderen Sammlung eingeschränkte Abfrage zu verarbeiten, darin, zuerst die Ergebnisse aus dieser Sammlung abzurufen und dann $in um nach dem zweiten zu filtern:

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

        }
    );

});

In früheren Releases ist dies also der einzige Weg, dies zu erreichen, indem die Liste gültiger Benutzer aus der anderen Sammlung an den Client gesendet wird und diese dann in einer Abfrage an die andere Sammlung weitergegeben wird.