Trên thực tế, cách "tốt nhất" để làm điều này là sử dụng .aggregate ()
và $ lookup
để "kết hợp" dữ liệu và "lọc" theo các điều kiện đối sánh. Điều này rất hiệu quả vì MongoDB thực sự thực hiện tất cả điều này trên chính "máy chủ", so với việc đưa ra các truy vấn "nhiều" dưới dạng .populate ()
không.
MovieModel.aggregate([
{ "$match": { "m_title": m_title } },
{ "$lookup": {
"from": RankMovieModel.collection.name,
"localField": "_id",
"foreignField": "movie",
"as": "rankings"
}}
])
Nếu có "nhiều" thứ hạng, thì tốt nhất bạn nên sử dụng $ unwind
, sẽ tạo một tài liệu cho từng mục "xếp hạng" có liên quan:
MovieModel.aggregate([
{ "$match": { "m_title": m_title } },
{ "$lookup": {
"from": RankMovieModel.collection.name,
"localField": "_id",
"foreignField": "movie",
"as": "rankings"
}},
{ "$unwind": "$rankings" }
])
Ở đây cũng có một cách xử lý đặc biệt về cách MongoDB xử lý với các tài liệu "gia nhập" để tránh vi phạm giới hạn 16MB BSON. Vì vậy, trên thực tế, điều đặc biệt này xảy ra khi $ unwind
trực tiếp theo dõi một $ tra cứu
giai đoạn đường ống:
{
"$lookup" : {
"from" : "rankmovies",
"as" : "rankings",
"localField" : "_id",
"foreignField" : "movie",
"unwinding" : {
"preserveNullAndEmptyArrays" : false
}
}
}
Vì vậy, $ unwind
thực sự "biến mất" và thay vào đó là "cuộn lại" thành $ tra cứu
như thể đây là hoạt động "một". Bằng cách đó, chúng tôi không tạo "mảng" trực tiếp trong tài liệu mẹ, điều này có thể khiến kích thước vượt quá 16MB trong trường hợp cực đoan với nhiều mục "liên quan".
Nếu bạn không có MongoDB hỗ trợ $ lookup
( MongoDB 3,2 phút ) thì bạn có thể sử dụng "ảo" với .populate ()
thay vào đó ( yêu cầu tối thiểu Mongoose 4.5.0 ). Nhưng lưu ý rằng điều này thực sự thực hiện "hai" truy vấn tới máy chủ:
Trước tiên, hãy thêm "ảo" vào giản đồ:
movieSchema.virtual("rankings",{
"ref": "Movie",
"localField": "_id",
"foreignField": "movie"
});
Sau đó, đưa ra truy vấn với .populate ()
:
MovieModel.find({ "m_title": m_title })
.populate('rankings')
.exec()