Nej, du kan inte anropa .populate()
före .aggregate()
, och det finns en mycket god anledning till varför du inte kan. Men det finns olika tillvägagångssätt du kan ta.
.populate()
Metoden fungerar "klientsidan" där den underliggande koden faktiskt utför ytterligare frågor (eller mer exakt en $in
query ) för att "söka upp" det eller de angivna elementen från den refererade samlingen.
Däremot .aggregate()
är en operation på "serversidan", så du kan i princip inte manipulera innehållet på "klientsidan" och sedan ha den informationen tillgänglig för aggregeringspipelinestadierna senare. Allt måste finnas i samlingen du opererar på.
Ett bättre tillvägagångssätt här är tillgängligt med MongoDB 3.2 och senare, via User
samling i detta fall för att begränsa urvalet:
User.aggregate(
[
// Filter first
{ "$match": {
"age": { "$gt": 20 }
}},
// Then join
{ "$lookup": {
"from": "scores",
"localField": "userID",
"foriegnField": "userID",
"as": "score"
}},
// More stages
],
function(err,results) {
}
)
Detta kommer i princip att inkludera ett nytt fält "poäng" i User
objekt som en "array" av objekt som matchade på "lookup" med den andra samlingen:
{
"userID": "abc",
"age": 21,
"score": [{
"userID": "abc",
"score": 42,
// other fields
}]
}
Resultatet är alltid en array, eftersom den generella förväntade användningen är en "vänsterkoppling" av en möjlig "en till många"-relation. Om inget resultat matchas är det bara en tom array.
För att använda innehållet, bara arbeta med en array på något sätt. Du kan till exempel använda $arrayElemAt
operatör för att bara få det enda första elementet i arrayen i framtida operationer. Och sedan kan du bara använda innehållet som vilket vanligt inbäddat fält som helst:
{ "$project": {
"userID": 1,
"age": 1,
"score": { "$arrayElemAt": [ "$score", 0 ] }
}}
Om du inte har MongoDB 3.2 tillgängligt, då är ditt andra alternativ för att bearbeta en fråga som begränsas av en annan samlings relationer att först hämta resultaten från den samlingen och sedan använda $in
för att filtrera på den andra:
// 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å genom att hämta listan över giltiga användare från den andra samlingen till klienten och sedan mata den till den andra samlingen i en fråga är det enda sättet att få detta att hända i tidigare utgåvor.