Ne, nemůžete volat .populate()
před .aggregate()
a existuje velmi dobrý důvod, proč nemůžete. Existují však různé přístupy, které můžete použít.
.populate()
metoda funguje „na straně klienta“, kde základní kód ve skutečnosti provádí další dotazy (nebo přesněji $in
query ) k "vyhledání" zadaného prvku (prvků) z odkazované kolekce.
Na rozdíl od toho .aggregate()
je operace "na straně serveru", takže v podstatě nemůžete manipulovat s obsahem "na straně klienta" a mít tato data k dispozici později pro fáze agregačního kanálu. To vše musí být přítomno ve sbírce, kterou provozujete.
Lepší přístup je k dispozici s MongoDB 3.2 a novějšími prostřednictvím $lookup
provoz agregačního potrubí. Také je pravděpodobně nejlepší zpracovat z User
kolekce v tomto případě za účelem zúžení výběru:
User.aggregate(
[
// Filter first
{ "$match": {
"age": { "$gt": 20 }
}},
// Then join
{ "$lookup": {
"from": "scores",
"localField": "userID",
"foriegnField": "userID",
"as": "score"
}},
// More stages
],
function(err,results) {
}
)
To v podstatě zahrnuje nové pole "skóre" v User
objekt jako "pole" položek, které se při "vyhledání" shodovaly s jinou sbírkou:
{
"userID": "abc",
"age": 21,
"score": [{
"userID": "abc",
"score": 42,
// other fields
}]
}
Výsledkem je vždy pole, protože obecně očekávané použití je „levé spojení“ možného vztahu „jedna k mnoha“. Pokud žádný výsledek neodpovídá, je to pouze prázdné pole.
Chcete-li použít obsah, stačí pracovat s polem jakýmkoli způsobem. Můžete například použít $arrayElemAt
operátora, aby bylo možné získat pouze jeden první prvek pole v budoucích operacích. A pak můžete obsah použít jako jakékoli normální vložené pole:
{ "$project": {
"userID": 1,
"age": 1,
"score": { "$arrayElemAt": [ "$score", 0 ] }
}}
Pokud nemáte k dispozici MongoDB 3.2, pak další možností, jak zpracovat dotaz omezený vztahy jiné kolekce, je nejprve získat výsledky z této kolekce a poté použít $in
pro filtrování podle druhého:
// 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) {
}
);
});
Jediným způsobem, jak toho dosáhnout v dřívějších verzích, je tedy získání seznamu platných uživatelů z druhé kolekce klientovi a jeho následné odeslání do jiné kolekce v dotazu.