Như bạn đã biết bây giờ, $ slice chỉ được sử dụng trong phép chiếu để giới hạn các phần tử mảng được trả về trong kết quả. Vì vậy, bạn sẽ gặp khó khăn với việc xử lý danh sách theo chương trình với kết quả từ find ().
Một cách tiếp cận tốt hơn là sử dụng tổng hợp. Nhưng trước tiên, hãy xem xét cách $ lát được sử dụng:
> db.collection.find({},{ relevancy: {$slice: -1} })
{ "_id" : ObjectId("530824b95f44eac1068b45c0"), "relevancy" : [ "Y" ] }
{ "_id" : ObjectId("530824b95f44eac1068b45c2"), "relevancy" : [ "Y" ] }
{ "_id" : ObjectId("530824b95f44eac1068b45c3"), "relevancy" : [ "N" ] }
{ "_id" : ObjectId("530824b95f44eac1068b45c4"), "relevancy" : [ "Y" ] }
{ "_id" : ObjectId("530824b95f44eac1068b45c6"), "relevancy" : [ "N" ] }
{ "_id" : ObjectId("530824b95f44eac1068b45c7"), "relevancy" : [ "N" ] }
{ "_id" : ObjectId("530824b95f44eac1068b45c8"), "relevancy" : [ "N" ] }
Vì vậy, bạn nhận được phần tử mảng cuối cùng, nhưng bạn gặp khó khăn với việc lặp lại các kết quả vì bạn không thể khớp giá trị phần tử cuối cùng. Bạn cũng có thể vừa thực hiện điều này trong mã.
Bây giờ chúng ta hãy xem xét tổng hợp :
db.collection.aggregate([
// Match things so we get rid of the documents that will never match, but it will
// still keep some of course since they are arrays, that *may* contain "N"
{ "$match": { "relevancy": "Y" } },
// De-normalizes the array
{ "$unwind": "$relevancy" },
// The order of the array is retained, so just look for the $last by _id
{ "$group": { "_id": "$_id", "relevancy": { "$last": "$relevancy" } }},
// Match only the records with the results you want
{ "$match": { "relevancy": "Y" }},
// Oh, and maintain the original _id order [ funny thing about $last ]
{ "$sort": { "_id": 1 } }
])
Ngay cả khi đây là lần đầu tiên bạn sử dụng tổng hợp (), tôi khuyến khích bạn tìm hiểu nó . Nó có lẽ là công cụ giải quyết vấn đề hữu ích nhất của bạn. Chắc chắn đã được cho tôi. Thực hiện từng bước trong một lần tại một thời điểm nếu bạn đang học.
Cũng không chắc chắn trên biểu mẫu tài liệu của bạn, tất cả 1: { ... }
ký hiệu tài liệu phụ dường như bị nhầm lẫn nhưng bạn nên xóa hoặc điều chỉnh mã ở trên để tham chiếu "1.relevancy"
thay thế. Tôi hy vọng tài liệu của bạn thực sự trông giống như thế này:
{ "relevancy" : [ "Y" ] , "_id" : ObjectId("530824b95f44eac1068b45c0") }
{ "relevancy" : [ "Y", "Y" ] , "_id" : ObjectId("530824b95f44eac1068b45c2") }
{ "relevancy" : [ "N" ], "_id" : ObjectId("530824b95f44eac1068b45c3") }
{ "relevancy" : [ "Y", "Y" ], "_id" : ObjectId("530824b95f44eac1068b45c4") }
{ "relevancy" : [ "Y", "N" ], "_id" : ObjectId("530824b95f44eac1068b45c6") }
{ "relevancy" : [ "N" ], "_id" : ObjectId("530824b95f44eac1068b45c7") }
{ "relevancy" : [ "Y", "N" ], "_id" : ObjectId("530824b95f44eac1068b45c8") }
MongoDB 3.2.x trở lên
Tất nhiên MongoDB 3.2 giới thiệu toán tử "tổng hợp" cho $slice
và $arrayElemAt
tốt hơn nữa toán tử loại bỏ sự cần thiết đối với bất kỳ $unwind
nào và $group
Chế biến. Sau $match
ban đầu truy vấn bạn chỉ cần tạo một "đối sánh logic" với $redact
:
db.collection.aggregate([
{ "$match": { "relevancy": "Y" } },
{ "$redact": {
"$cond": {
"if": { "$eq": [{ "$arrayElemAt": [ "$relevancy", -1 ], "Y" ] },
"then": "$$KEEP",
"else": "$$PRUNE"
}
}}
])
Điều đó sẽ thực hiện kiểm tra phần tử cuối cùng của mảng khi quyết định có nên $$KEEP
hay không hoặc $$PRUNE
các tài liệu từ kết quả trả về.
Nếu bạn vẫn muốn "phép chiếu" thì bạn thực sự có thể thêm $slice
:
db.collection.aggregate([
{ "$match": { "relevancy": "Y" } },
{ "$redact": {
"$cond": {
"if": { "$eq": [{ "$arrayElemAt": [ "$relevancy", -1 ], "Y" ] },
"then": "$$KEEP",
"else": "$$PRUNE"
}
}},
{ "$project": { "relevancy": { "$slice": [ "$relevancy", -1 ] } } }
])
Hoặc cách tiếp cận thay thế của:
db.collection.aggregate([
{ "$match": { "relevancy": "Y" } },
{ "$project": { "relevancy": { "$slice": [ "$relevancy", -1 ] } } },
{ "$match": { "relevancy": "Y" } }
])
Nhưng có lẽ ít tốn kém hơn khi thực hiện $redact
đầu tiên và "sau đó" thực hiện bất kỳ sự định hình lại nào trong `$ project.