Zoals je inmiddels weet, wordt $slice alleen gebruikt in projectie om de array-elementen die in de resultaten worden geretourneerd, te beperken. Je zou dus vast zitten aan het programmatisch verwerken van de lijst met resultaten van een find().
Een betere benadering is om aggregaat te gebruiken. Maar laten we eerst eens kijken hoe $slice wordt gebruikt:
> 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" ] }
Dus je krijgt het laatste array-element, maar je zit vast met het herhalen van de resultaten omdat je niet kunt matchen de laatste elementwaarde. Je had dit net zo goed in code kunnen doen.
Laten we nu eens kijken naar totaal :
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 } }
])
Zelfs als dit je eerste gebruik van aggregate() zou zijn, raad ik je aan om het te leren . Het is misschien wel uw meest bruikbare hulpmiddel voor het oplossen van problemen. Zeker voor mij geweest. Zet elke stap eenmaal tegelijk als je aan het leren bent.
Ook niet zeker op uw documentformulier, alle 1: { ... }
subdocumentnotatie lijkt een fout te zijn, maar u moet dat ophelderen of de bovenstaande code aanpassen om te verwijzen naar "1.relevancy"
in plaats van. Ik hoop echter dat uw documenten er in werkelijkheid meer zo uitzien:
{ "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 en hoger
Natuurlijk introduceert MongoDB 3.2 een "aggregatie"-operator voor $slice
en een nog betere $arrayElemAt
operator die de noodzaak voor $unwind
. wegneemt en $group
verwerken. Na de eerste $match
vraag maak je gewoon een "logische match" met $redact
:
db.collection.aggregate([
{ "$match": { "relevancy": "Y" } },
{ "$redact": {
"$cond": {
"if": { "$eq": [{ "$arrayElemAt": [ "$relevancy", -1 ], "Y" ] },
"then": "$$KEEP",
"else": "$$PRUNE"
}
}}
])
Dat gaat de inspectie van het laatste element van de array doen bij het beslissen of $$KEEP
of $$PRUNE
de documenten van de geretourneerde resultaten.
Als je nog steeds de "projectie" wilt, dan kun je de $slice
. toevoegen :
db.collection.aggregate([
{ "$match": { "relevancy": "Y" } },
{ "$redact": {
"$cond": {
"if": { "$eq": [{ "$arrayElemAt": [ "$relevancy", -1 ], "Y" ] },
"then": "$$KEEP",
"else": "$$PRUNE"
}
}},
{ "$project": { "relevancy": { "$slice": [ "$relevancy", -1 ] } } }
])
Of de alternatieve benadering van:
db.collection.aggregate([
{ "$match": { "relevancy": "Y" } },
{ "$project": { "relevancy": { "$slice": [ "$relevancy", -1 ] } } },
{ "$match": { "relevancy": "Y" } }
])
Maar het is waarschijnlijk minder duur om de $redact
. te doen doe eerst en "dan" een nieuwe vorm in `$project.