Som du ved nu, bruges $slice kun i projektion for at begrænse de array-elementer, der returneres i resultaterne. Så du ville sidde fast med at behandle listen programmatisk med resultater fra en find().
En bedre tilgang er at bruge aggregat. Men lad os først overveje, hvordan $slice bruges:
> 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" ] }
Så du får det sidste array-element, men du sidder fast med at sløjfe resultaterne, da du ikke kan matche den sidste elementværdi. Du kunne lige så godt bare have gjort dette i kode.
Lad os nu se på samlet :
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 } }
])
Selvom dette ville være din første brug af aggregate(), opfordrer jeg dig til at lære det . Det er måske dit mest nyttige problemløsningsværktøj. Det har det bestemt været for mig. Indsæt hvert trin én gang ad gangen, hvis du lærer.
Er heller ikke sikker på din dokumentformular, alle 1: { ... }
underdokumentnotation ser ud til at være en fejl, men du bør rydde op eller justere koden ovenfor for at referere til "1.relevancy"
i stedet. Jeg håber dog, at dine dokumenter faktisk ser mere sådan ud:
{ "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 og nyere
Selvfølgelig introducerer MongoDB 3.2 en "aggregation"-operator for $slice
og en endnu bedre $arrayElemAt
operatør, der fjerner behovet for enhver $unwind
og $group
forarbejdning. Efter den indledende $match
forespørgsel laver du bare et "logisk match" med $redact
:
db.collection.aggregate([
{ "$match": { "relevancy": "Y" } },
{ "$redact": {
"$cond": {
"if": { "$eq": [{ "$arrayElemAt": [ "$relevancy", -1 ], "Y" ] },
"then": "$$KEEP",
"else": "$$PRUNE"
}
}}
])
Det vil foretage inspektionen af det sidste element i arrayet, når det besluttes om $$KEEP
skal eller $$PRUNE
dokumenterne fra de returnerede resultater.
Hvis du stadig ville have "projektionen", kan du faktisk tilføje $slice
:
db.collection.aggregate([
{ "$match": { "relevancy": "Y" } },
{ "$redact": {
"$cond": {
"if": { "$eq": [{ "$arrayElemAt": [ "$relevancy", -1 ], "Y" ] },
"then": "$$KEEP",
"else": "$$PRUNE"
}
}},
{ "$project": { "relevancy": { "$slice": [ "$relevancy", -1 ] } } }
])
Eller den alternative tilgang til:
db.collection.aggregate([
{ "$match": { "relevancy": "Y" } },
{ "$project": { "relevancy": { "$slice": [ "$relevancy", -1 ] } } },
{ "$match": { "relevancy": "Y" } }
])
Men det er sandsynligvis mindre omkostningsfuldt at lave $redact
først og "derefter" udfører enhver omformning i `$project.