Bạn không thể trả về nhiều phần tử của một mảng phù hợp với tiêu chí của mình ở bất kỳ dạng nào của .find()
cơ bản truy vấn. Để khớp với nhiều phần tử, bạn cần sử dụng .aggregate()
thay vào đó.
Sự khác biệt chính ở đây là "truy vấn" thực hiện chính xác những gì nó dự định làm và khớp với "tài liệu" đáp ứng các điều kiện của bạn. Bạn có thể thử sử dụng $
vị trí trong một đối số chiếu, nhưng các quy tắc ở đó là nó sẽ chỉ khớp với phần tử mảng "đầu tiên" khớp với các điều kiện truy vấn.
Để "lọc" nhiều phần tử mảng, hãy tiến hành như sau:
db.sample.aggregate([
// Filter possible documents
{ "$match": { "filtermetric.class": "s2" } },
// Unwind the array to denormalize
{ "$unwind": "$filtermetric" },
// Match specific array elements
{ "$match": { "filtermetric.class": "s2" } },
// Group back to array form
{ "$group": {
"_id": "$_id",
"filtermetric": { "$push": "$filtermetric" }
}}
])
Trong các phiên bản hiện đại của MongoDB là phiên bản 2.6 trở lên, bạn có thể thực hiện việc này với $redact
:
db.sample.aggregate([
// Filter possible documents
{ "$match": { "filtermetric.class": "s2" } },
// Redact the entries that do not match
{ "$redact": {
"$cond": [
{ "$eq": [ { "$ifNull": [ "$class", "s2" ] }, "s2" ] },
"$$DESCEND",
"$$PRUNE"
]
}}
])
Đó có lẽ là tùy chọn hiệu quả nhất của bạn, nhưng nó là đệ quy, vì vậy hãy xem xét cấu trúc tài liệu của bạn trước tiên vì cùng một trường được đặt tên không thể tồn tại với bất kỳ điều kiện nào khác ở bất kỳ cấp độ nào.
Có thể an toàn hơn nhưng chỉ hữu ích khi kết quả trong mảng là "thực sự duy nhất" là kỹ thuật này với $map
và $setDifference
:
db.sample.aggregate([
{ "$project": {
"filtermetric": { "$setDifference": [
{ "$map": [
"input": "$filtermetric",
"as": "el",
"in": {"$cond": [
{ "$eq": [ "$$el.class", "s2" ] },
"$$el",
false
]}
]},
[false]
]}
}}
])
Cũng lưu ý rằng trong cả $group
và $project
các giai đoạn vận hành mà bạn cần để chỉ định tất cả các trường bạn định trả về trong tài liệu kết quả của mình từ giai đoạn đó.
Lưu ý cuối cùng là $elemMatch
không bắt buộc khi bạn chỉ truy vấn giá trị của một khóa duy nhất trong một mảng. "Ký hiệu dấu chấm" được ưu tiên và khuyến nghị khi chỉ truy cập một khóa duy nhất của mảng. $elemMatch
chỉ nên cần thiết khi "nhiều" khóa trong tài liệu trong mảng "phần tử" cần khớp với điều kiện truy vấn.