Nej, du kan ikke kalde .populate()
før .aggregate()
, og der er en meget god grund til, at du ikke kan. Men der er forskellige tilgange, du kan tage.
.populate()
metoden fungerer på "klientsiden", hvor den underliggende kode faktisk udfører yderligere forespørgsler (eller mere præcist en $in
query ) for at "slå op" det eller de specificerede element(er) fra den refererede samling.
I modsætning hertil .aggregate()
er en "serverside"-operation, så du kan dybest set ikke manipulere indholdet "klientside", og så have disse data tilgængelige for aggregeringspipeline-stadierne senere. Det hele skal være til stede i den samling, du opererer på.
En bedre tilgang her er tilgængelig med MongoDB 3.2 og nyere via Bruger
samling i dette tilfælde for at indsnævre udvalget:
User.aggregate(
[
// Filter first
{ "$match": {
"age": { "$gt": 20 }
}},
// Then join
{ "$lookup": {
"from": "scores",
"localField": "userID",
"foriegnField": "userID",
"as": "score"
}},
// More stages
],
function(err,results) {
}
)
Dette vil grundlæggende inkludere et nyt felt "score" i Bruger
objekt som en "array" af elementer, der matchede på "opslag" til den anden samling:
{
"userID": "abc",
"age": 21,
"score": [{
"userID": "abc",
"score": 42,
// other fields
}]
}
Resultatet er altid et array, da den generelle forventede brug er en "venstresammenføjning" af et muligt "en til mange"-forhold. Hvis intet resultat matches, er det bare et tomt array.
For at bruge indholdet skal du bare arbejde med et array på nogen måde. For eksempel kan du bruge $arrayElemAt
operatør for blot at få det enkelte første element i arrayet i eventuelle fremtidige operationer. Og så kan du bare bruge indholdet som et hvilket som helst normalt indlejret felt:
{ "$project": {
"userID": 1,
"age": 1,
"score": { "$arrayElemAt": [ "$score", 0 ] }
}}
Hvis du ikke har MongoDB 3.2 tilgængelig, så er din anden mulighed for at behandle en forespørgsel begrænset af relationerne til en anden samling først at hente resultaterne fra den samling og derefter bruge $in
for at filtrere på den anden:
// 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) {
}
);
});
Så ved at få listen over gyldige brugere fra den anden samling til klienten og derefter føre den til den anden samling i en forespørgsel er den eneste måde at få dette til at ske i tidligere udgivelser.