Agregační rámec prostě „nezachází s“ poli stejným způsobem, jaký je aplikován na .find()
dotazy obecně. To neplatí pouze pro operace jako .sort()
, ale i s jinými operátory, a to konkrétně $slice
, ačkoli tento příklad bude brzy opraven (více později).
Takže je téměř nemožné vypořádat se s čímkoli pomocí "tečkové notace" formy s indexem pozice pole, jako máte vy. Ale existuje způsob, jak to obejít.
Co "můžete" udělat, je v podstatě zjistit, co je vlastně "n-tý" prvek pole jako hodnotu, a pak to vrátit jako pole, které lze třídit:
db.test.aggregate([
{ "$unwind": "$items" },
{ "$group": {
"_id": "$_id",
"items": { "$push": "$items" },
"itemsCopy": { "$push": "$items" },
"first": { "$first": "$items" }
}},
{ "$unwind": "$itemsCopy" },
{ "$project": {
"items": 1,
"itemsCopy": 1,
"first": 1,
"seen": { "$eq": [ "$itemsCopy", "$first" ] }
}},
{ "$match": { "seen": false } },
{ "$group": {
"_id": "$_id",
"items": { "$first": "$items" },
"itemsCopy": { "$push": "$itemsCopy" },
"first": { "$first": "$first" },
"second": { "$first": "$itemsCopy" }
}},
{ "$sort": { "second": -1 } }
])
Je to hrozný a „opakovatelný“ přístup, kdy v podstatě „procházíte“ každý prvek pole získáním $first
shodu na dokument z pole po zpracování pomocí $ uvolnit
. Poté po $unwind
znovu otestujete, zda jsou tyto prvky pole stejné jako ty, které již byly "viděny" z identifikovaných pozic pole.
Je to hrozné a horší pro více pozic, na kterých se chcete pohybovat, ale má to výsledek:
{ "_id" : 2, "items" : [ 0, 3, 4 ], "itemsCopy" : [ 3, 4 ], "first" : 0, "second" : 3 }
{ "_id" : 1, "items" : [ 1, 2, 0 ], "itemsCopy" : [ 2, 0 ], "first" : 1, "second" : 2 }
{ "_id" : 3, "items" : [ 2, 1, 5 ], "itemsCopy" : [ 1, 5 ], "first" : 2, "second" : 1 }
Naštěstí nadcházející vydání MongoDB (jak je aktuálně k dispozici ve vývojových verzích) dostanou „opravu“. Nemusí to být "dokonalá" oprava, kterou si přejete, ale řeší základní problém.
Je zde nový $slice
operátor dostupný pro tamní agregační rámec a vrátí požadované prvky pole z indexovaných pozic:
db.test.aggregate([
{ "$project": {
"items": 1,
"slice": { "$slice": [ "$items",1,1 ] }
}},
{ "$sort": { "slice": -1 } }
])
Což produkuje:
{ "_id" : 2, "items" : [ 0, 3, 4 ], "slice" : [ 3 ] }
{ "_id" : 1, "items" : [ 1, 2, 0 ], "slice" : [ 2 ] }
{ "_id" : 3, "items" : [ 2, 1, 5 ], "slice" : [ 1 ] }
Můžete si tedy všimnout, že jako „slice“ je výsledkem stále „pole“, nicméně $sort
v agregačním rámci vždy používal "první pozici" pole, aby seřadil obsah. To znamená, že se singulární hodnotou extrahovanou z indexované pozice (stejně jako dlouhý postup výše) bude výsledek seřazen podle očekávání.
Zde jsou konečné případy, jak to funguje. Buď žijte s druhem operací, které shora potřebujete, abyste mohli pracovat s indexovanou pozicí pole, nebo „počkejte“, až vás zachrání zbrusu nová nablýskaná verze s lepšími operátory.