No nie można nazwać .populate()
przed .aggregate()
, i jest to bardzo dobry powód, dlaczego nie można. Ale są różne podejścia, które możesz podjąć.
Metoda ta działa "po stronie klienta", gdzie podstawowy kod faktycznie wykonuje dodatkowe kwerendy (lub dokładniej kwerendę $in
) w celu "wyszukiwania" określonych elementów z przywoływanej kolekcji.
W przeciwieństwie do tego, jest operacją "po stronie serwera", więc zasadniczo nie można manipulować treścią "po stronie klienta", a następnie udostępniać te dane w etapach potoku agregacji później. To wszystko musi być obecne w kolekcji, w której pracujesz.
Lepsza metoda dostępna jest tutaj z MongoDB 3.2 i nowszymi, za pośrednictwem operacji agregacji potoku $lookup
. Także chyba najlepiej poradzić z kolekcji User
w tym przypadku w celu zawężenia wybór:
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 jest w zasadzie będzie to nowe pole „gola” w ramach przedmiotu User
jako „tablica” przedmiotów które odpowiadają na „odnośnika” do innej kolekcji:
{
"userID": "abc",
"age": 21,
"score": [{
"userID": "abc",
"score": 42,
// other fields
}]
}
wynik jest zawsze tablicą, jako ogólna oczekiwane wykorzystanie jest „left join” ewentualnej „jeden do wielu” relacji. Jeśli nie zostanie dopasowany żaden wynik, jest to po prostu pusta tablica.
Aby użyć treści, po prostu pracuj z tablicą w jakikolwiek sposób. Na przykład możesz użyć operatora $arrayElemAt
, aby uzyskać pojedynczy pierwszy element tablicy w przyszłych operacjach. A następnie możesz po prostu użyć zawartości jak normalnego osadzonego pola:
{ "$project": {
"userID": 1,
"age": 1,
"score": { "$arrayElemAt": [ "$score", 0 ] }
}}
Jeśli nie masz MongoDB 3.2 dostępny, wówczas inna opcja przetwarzać zapytania ograniczony przez stosunki innej kolekcji jest, aby najpierw uzyskać wyniki z tej kolekcji, a następnie użyć $in
filtrować na drugi:
// 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) {
}
);
});
to poprzez uzyskanie listy poprawni użytkownicy z drugiej kolekcji do klienta, a następnie dostarczenie ich do innej kolekcji w zapytaniu, to jedyny sposób, aby to zrobić we wcześniejszych wersjach.
jeśli userList jest tablicą objectId, czy musisz przekonwertować je na łańcuchy znaków –
jesteś inteligentnym facetem, ale 'foriegnField' powinno być' foreignField', jak sądzę. nie ma sprawy –