Các truy vấn chuẩn không thể "so sánh" các giá trị trong tài liệu. Đây thực sự là điều bạn làm bằng cách sử dụng .aggregate()
và $redact
:
db.collection.aggregate([
{ "$redact": {
"$cond": {
"if": {
"$gt": [
{ "$size": {
"$filter": {
"input": "$offers",
"as": "o",
"cond": { "$eq": [ "$$o.amount", "$amount" ] }
}
}},
0
]
},
"then": "$$KEEP",
"else": "$$PRUNE"
}
}}
])
Ở đây chúng tôi sử dụng $filter
để so sánh các giá trị của "amount"
trong tài liệu mẹ cho những người trong mảng. Nếu ít nhất một "bằng" thì chúng tôi "$$KEEP"
tài liệu, nếu không, chúng tôi "$$PRUNE"
Trong hầu hết các phiên bản gần đây, chúng tôi có thể rút ngắn điều đó bằng cách sử dụng $indexOfArray
.
db.collection.aggregate([
{ "$redact": {
"$cond": {
"if": {
"$ne": [
{ "$indexOfArray": [ "$offers.amount", "$amount" ] },
-1
]
},
"then": "$$KEEP",
"else": "$$PRUNE"
}
}}
])
Nếu bạn thực sự chỉ muốn "(các) phần tử mảng phù hợp", thì bạn sẽ thêm $filter
trong phép chiếu:
db.collection.aggregate([
{ "$redact": {
"$cond": {
"if": {
"$gt": [
{ "$size": {
"$filter": {
"input": "$offers",
"as": "o",
"cond": { "$eq": [ "$$o.amount", "$amount" ] }
}
}},
0
]
},
"then": "$$KEEP",
"else": "$$PRUNE"
}
}},
{ "$project": {
"amount": 1,
"offers": {
"$filter": {
"input": "$offers",
"as": "o",
"cond": { "$eq": [ "$$o.amount", "$amount" ] }
}
}
}}
])
Nhưng nguyên tắc chính tất nhiên là để "giảm" số lượng tài liệu trả về chỉ những thứ thực sự phù hợp với điều kiện là ưu tiên "đầu tiên". Nếu không, bạn chỉ đang thực hiện các tính toán không cần thiết và công việc tốn thời gian và tài nguyên, cho kết quả mà sau này bạn sẽ loại bỏ.
Vì vậy, "lọc" đầu tiên và "định hình lại" thứ hai là ưu tiên.