Tidak, Anda tidak dapat memanggil .populate()
sebelum .aggregate()
, dan ada alasan yang sangat bagus mengapa Anda tidak bisa. Tapi ada pendekatan berbeda yang bisa Anda ambil.
.populate()
metode bekerja "sisi klien" di mana kode yang mendasarinya benar-benar melakukan kueri tambahan (atau lebih tepatnya $in
query ) untuk "mencari" elemen tertentu dari koleksi yang direferensikan.
Sebaliknya .aggregate()
adalah operasi "sisi server", jadi pada dasarnya Anda tidak dapat memanipulasi konten "sisi klien", dan kemudian memiliki data yang tersedia untuk tahap pipa agregasi nanti. Semuanya harus ada dalam koleksi yang Anda operasikan.
Pendekatan yang lebih baik di sini tersedia dengan MongoDB 3.2 dan yang lebih baru, melalui $lookup
operasi pipa agregasi. Juga mungkin yang terbaik untuk ditangani dari User
koleksi dalam hal ini untuk mempersempit pilihan:
User.aggregate(
[
// Filter first
{ "$match": {
"age": { "$gt": 20 }
}},
// Then join
{ "$lookup": {
"from": "scores",
"localField": "userID",
"foriegnField": "userID",
"as": "score"
}},
// More stages
],
function(err,results) {
}
)
Ini pada dasarnya akan menyertakan "skor" bidang baru di dalam User
objek sebagai "array" item yang cocok pada "pencarian" ke koleksi lain:
{
"userID": "abc",
"age": 21,
"score": [{
"userID": "abc",
"score": 42,
// other fields
}]
}
Hasilnya selalu berupa array, karena penggunaan yang diharapkan secara umum adalah "gabungan kiri" dari kemungkinan hubungan "satu ke banyak". Jika tidak ada hasil yang cocok maka itu hanya array kosong.
Untuk menggunakan konten, cukup bekerja dengan array dengan cara apa pun. Misalnya, Anda dapat menggunakan $arrayElemAt
operator untuk mendapatkan satu elemen pertama dari array dalam operasi apa pun di masa mendatang. Dan kemudian Anda bisa menggunakan konten seperti bidang tersemat biasa:
{ "$project": {
"userID": 1,
"age": 1,
"score": { "$arrayElemAt": [ "$score", 0 ] }
}}
Jika Anda tidak memiliki MongoDB 3.2, maka opsi Anda yang lain untuk memproses kueri yang dibatasi oleh relasi dari koleksi lain adalah dengan terlebih dahulu mendapatkan hasil dari koleksi tersebut dan kemudian menggunakan $in
untuk memfilter yang kedua:
// 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) {
}
);
});
Jadi dengan mendapatkan daftar pengguna yang valid dari koleksi lain ke klien dan kemudian memasukkannya ke koleksi lain dalam kueri adalah satu-satunya cara untuk mewujudkannya di rilis sebelumnya.