Jak již víte, $slice se používá pouze v projekci k omezení prvků pole vrácených ve výsledcích. Takže byste se zasekli u programového zpracování seznamu s výsledky z find().
Lepším přístupem je použití agregátu. Nejprve se však podívejme, jak $slice se používá:
> 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" ] }
Získáte tedy poslední prvek pole, ale zaseknete se u opakování výsledků, protože se nemůžete shodovat hodnotu posledního prvku. Možná jste to právě udělali v kódu.
Nyní se podíváme na agregát :
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 } }
])
I když by to bylo vaše první použití agregátu(), doporučuji vám, abyste se naučili . Je to možná váš nejužitečnější nástroj pro řešení problémů. Pro mě určitě bylo. Vložte každý krok jednou v době, kdy se učíte.
Také si nejste jisti ve formuláři dokumentu, zda všechny 1: { ... }
zápis dílčího dokumentu se zdá být chybný, ale měli byste to vyčistit nebo upravit výše uvedený kód tak, aby odkazoval na "1.relevancy"
namísto. Doufám, že vaše dokumenty ve skutečnosti vypadají spíše takto:
{ "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.xa novější
MongoDB 3.2 samozřejmě zavádí operátor „agregace“ pro $slice
a ještě lepší $arrayElemAt
operátor, který odstraňuje potřebu jakéhokoli $unwind
a $group
zpracovává se. Po úvodním $match
stačí vytvořit "logickou shodu" s $redact
:
db.collection.aggregate([
{ "$match": { "relevancy": "Y" } },
{ "$redact": {
"$cond": {
"if": { "$eq": [{ "$arrayElemAt": [ "$relevancy", -1 ], "Y" ] },
"then": "$$KEEP",
"else": "$$PRUNE"
}
}}
])
To provede kontrolu na posledním prvku pole při rozhodování, zda $$KEEP
nebo $$PRUNE
dokumenty z vrácených výsledků.
Pokud byste stále chtěli "projekci", můžete skutečně přidat $slice
:
db.collection.aggregate([
{ "$match": { "relevancy": "Y" } },
{ "$redact": {
"$cond": {
"if": { "$eq": [{ "$arrayElemAt": [ "$relevancy", -1 ], "Y" ] },
"then": "$$KEEP",
"else": "$$PRUNE"
}
}},
{ "$project": { "relevancy": { "$slice": [ "$relevancy", -1 ] } } }
])
Nebo alternativní přístup:
db.collection.aggregate([
{ "$match": { "relevancy": "Y" } },
{ "$project": { "relevancy": { "$slice": [ "$relevancy", -1 ] } } },
{ "$match": { "relevancy": "Y" } }
])
Ale je pravděpodobně méně nákladné provést $redact
nejprve a "pak" proveďte jakoukoli změnu tvaru v `$project.