Jak już wiesz, $slice jest używany tylko w projekcji, aby ograniczyć liczbę elementów tablicy zwracanych w wynikach. Więc utknąłbyś z programowym przetwarzaniem listy z wynikami z find().
Lepszym podejściem jest użycie agregatu. Ale najpierw zastanówmy się, jak $slice jest używany:
> 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" ] }
Otrzymujesz więc ostatni element tablicy, ale utkniesz z zapętleniem wyników, ponieważ nie możesz dopasować ostatnia wartość elementu. Równie dobrze mogłeś to zrobić w kodzie.
Spójrzmy teraz na agregację :
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 } }
])
Nawet jeśli byłoby to Twoje pierwsze użycie agregacji(), zachęcam Cię do nauczenia się tego . Jest to prawdopodobnie najbardziej przydatne narzędzie do rozwiązywania problemów. Na pewno był dla mnie. Umieść każdy krok raz na raz, jeśli się uczysz.
Również nie jestem pewien w formularzu dokumentu, wszystkie 1: { ... }
Notacja dokumentu podrzędnego wydaje się być błędna, ale powinieneś to wyjaśnić lub dostosować powyższy kod, aby odwoływał się do "1.relevancy"
zamiast. Mam jednak nadzieję, że Twoje dokumenty rzeczywiście wyglądają tak:
{ "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 i nowsze
Oczywiście MongoDB 3.2 wprowadza operator „agregacji” dla $slice
i jeszcze lepszy $arrayElemAt
operator, który eliminuje potrzebę jakiegokolwiek $unwind
i $group
przetwarzanie. Po początkowym $match
zapytanie po prostu tworzysz „logiczne dopasowanie” za pomocą $redact
:
db.collection.aggregate([
{ "$match": { "relevancy": "Y" } },
{ "$redact": {
"$cond": {
"if": { "$eq": [{ "$arrayElemAt": [ "$relevancy", -1 ], "Y" ] },
"then": "$$KEEP",
"else": "$$PRUNE"
}
}}
])
Spowoduje to sprawdzenie ostatniego elementu tablicy podczas podejmowania decyzji, czy $$KEEP
lub $$PRUNE
dokumenty ze zwróconych wyników.
Jeśli nadal chcesz „projekcja”, możesz dodać $slice
:
db.collection.aggregate([
{ "$match": { "relevancy": "Y" } },
{ "$redact": {
"$cond": {
"if": { "$eq": [{ "$arrayElemAt": [ "$relevancy", -1 ], "Y" ] },
"then": "$$KEEP",
"else": "$$PRUNE"
}
}},
{ "$project": { "relevancy": { "$slice": [ "$relevancy", -1 ] } } }
])
Lub alternatywne podejście:
db.collection.aggregate([
{ "$match": { "relevancy": "Y" } },
{ "$project": { "relevancy": { "$slice": [ "$relevancy", -1 ] } } },
{ "$match": { "relevancy": "Y" } }
])
Ale prawdopodobnie mniej kosztowne jest wykonanie $redact
najpierw, a następnie „następnie” dokonaj zmiany kształtu w `$project.