Tôi biết câu hỏi này đã cũ nhưng tôi đã tìm thấy câu hỏi này trên google sau khi trả lời một câu hỏi mới tương tự . Vì vậy, tôi nghĩ điều này xứng đáng được đối xử tương tự.
Bạn có thể tránh ảnh hưởng hiệu suất của $ where bằng cách sử dụng tổng hợp thay vào đó:
db.example.aggregate([
// Use an index, which $where cannot to narrow down
{$match: { "comments.by": "Abe" }},
// De-normalize the Array
{$unwind: "$comments"},
// The order of the array is maintained, so just look for the $last by _id
{$group: { _id: "$_id", comments: {$last: "$comment"} }},
// Match only where that $last comment by `by.Abe`
{$match: { "comments.by": "Abe" }},
// Retain the original _id order
{$sort: { _id: 1 }}
])
Và điều đó sẽ chạy vòng quanh $ where vì chúng tôi có thể thu hẹp các tài liệu có một bình luận của "Abe" ở vị trí đầu tiên. Như đã cảnh báo, $ where sẽ kiểm tra mọi tài liệu trong bộ sưu tập và không bao giờ sử dụng chỉ mục ngay cả khi tài liệu đó được sử dụng.
Tất nhiên, bạn cũng có thể duy trì tài liệu gốc bằng cách sử dụng kỹ thuật được mô tả tại đây
cũng vậy, vì vậy mọi thứ sẽ hoạt động giống như find()
.
Chỉ là thức ăn để suy nghĩ cho bất kỳ ai tìm thấy thứ này.
Cập nhật cho các bản phát hành MongoDB hiện đại
Các bản phát hành hiện đại đã thêm $redact
biểu thức đường ống cũng như $arrayElemAt
(cái sau kể từ 3.2, vì vậy đó sẽ là phiên bản tối thiểu ở đây) khi kết hợp sẽ cho phép biểu thức logic kiểm tra phần tử cuối cùng của mảng mà không cần xử lý $unwind
giai đoạn:
db.example.aggregate([
{ "$match": { "comments.by": "Abe" }},
{ "$redact": {
"$cond": {
"if": {
"$eq": [
{ "$arrayElemAt": [ "$comments.by", -1 ] },
"Abe"
]
},
"then": "$$KEEP",
"else": "$$PRUNE"
}
}}
])
Logic ở đây được thực hiện so với $arrayElemAt
đang nhận chỉ mục cuối cùng của mảng -1
, được chuyển đổi chỉ thành một mảng các giá trị trong "by"
thuộc tính qua $map
. Điều này cho phép so sánh giá trị đơn lẻ với tham số bắt buộc, "Abe"
.
Hoặc thậm chí hiện đại hơn một chút bằng cách sử dụng $expr
cho MongoDB 3.6 trở lên:
db.example.find({
"comments.by": "Abe",
"$expr": {
"$eq": [
{ "$arrayElemAt": [ "$comments.by", -1 ] },
"Abe"
]
}
})
Đây sẽ là giải pháp hiệu quả nhất để so khớp phần tử cuối cùng trong một mảng và thực sự được mong đợi sẽ thay thế việc sử dụng $where
trong hầu hết các trường hợp và đặc biệt là ở đây.