Не, не можете да извикате .populate()
преди .aggregate()
и има много добра причина да не можете. Но има различни подходи, които можете да предприемете.
.populate()
методът работи от страна на клиента, където основният код всъщност изпълнява допълнителни заявки (или по-точно $in
query ), за да „потърсите“ посочения(те) елемент(и) от референтната колекция.
За разлика от .aggregate()
е операция от страна на сървъра, така че по същество не можете да манипулирате съдържание от страна на клиента и след това да разполагате с тези данни за етапите на тръбопровода за агрегиране по-късно. Всичко това трябва да присъства в колекцията, с която работите.
По-добър подход тук е наличен с MongoDB 3.2 и по-нови версии, чрез $lookup
работа на тръбопровод за агрегиране. Вероятно е най-добре да се работи от User
колекция в този случай, за да стесните избора:
User.aggregate(
[
// Filter first
{ "$match": {
"age": { "$gt": 20 }
}},
// Then join
{ "$lookup": {
"from": "scores",
"localField": "userID",
"foriegnField": "userID",
"as": "score"
}},
// More stages
],
function(err,results) {
}
)
Това основно ще включва ново поле "резултат" в User
обект като "масив" от елементи, които съответстват при "търсене" на другата колекция:
{
"userID": "abc",
"age": 21,
"score": [{
"userID": "abc",
"score": 42,
// other fields
}]
}
Резултатът винаги е масив, тъй като общото очаквано използване е "ляво съединение" на възможна връзка "едно към много". Ако няма съответстващ резултат, това е просто празен масив.
За да използвате съдържанието, просто работете с масив по какъвто и да е начин. Например можете да използвате $arrayElemAt
оператор, за да получите само първия елемент от масива при всякакви бъдещи операции. И тогава можете просто да използвате съдържанието като всяко нормално вградено поле:
{ "$project": {
"userID": 1,
"age": 1,
"score": { "$arrayElemAt": [ "$score", 0 ] }
}}
Ако не разполагате с MongoDB 3.2, тогава другата ви опция за обработка на заявка, ограничена от отношенията на друга колекция, е първо да получите резултатите от тази колекция и след това да използвате $in
за филтриране на втория:
// 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) {
}
);
});
Така че получаването на списъка с валидни потребители от другата колекция на клиента и след това подаването му на другата колекция в заявка е единственият начин това да се случи в по-ранни версии.