Рамката за агрегиране просто не "работи" с масиви по същия начин, както се прилага към .find()
заявки като цяло. Това не е вярно само за операции като .sort()
, но също и с други оператори, а именно $sliceкод>
, въпреки че този пример е на път да получи корекция (повече по-късно).
Така че е почти невъзможно да се справим с каквото и да било, използвайки формата за "точкова нотация" с индекс на позиция на масив, какъвто имате. Но има начин да се заобиколи това.
Това, което „можете“ да направите, е основно да разберете какво всъщност представлява „n-тият“ елемент от масива като стойност и след това да го върнете като поле, което може да бъде сортирано:
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 } }
])
Това е ужасен и „итерируем“ подход, при който по същество „минавате през“ всеки елемент от масива, като получавате $first
съвпадение на документ от масива след обработка с $ размотавам
. След това след $unwind
отново тествате, за да видите дали тези елементи на масива са същите като този(ите), които вече са „виждани“ от идентифицираните позиции на масива.
Ужасно е и още по-лошо за колкото повече позиции искате да се придвижите, но резултатът се получава:
{ "_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 }
За щастие, предстоящите издания на MongoDB (както в момента са налични в изданията за разработка) получават „поправка“ за това. Може да не е „идеалното“ решение, което желаете, но решава основния проблем.
Има нов $slice
оператор, наличен за рамката за агрегиране там, и ще върне необходимия елемент(и) на масива от индексираните позиции:
db.test.aggregate([
{ "$project": {
"items": 1,
"slice": { "$slice": [ "$items",1,1 ] }
}},
{ "$sort": { "slice": -1 } }
])
Което произвежда:
{ "_id" : 2, "items" : [ 0, 3, 4 ], "slice" : [ 3 ] }
{ "_id" : 1, "items" : [ 1, 2, 0 ], "slice" : [ 2 ] }
{ "_id" : 3, "items" : [ 2, 1, 5 ], "slice" : [ 1 ] }
Така че можете да отбележите, че като "срез", резултатът все още е "масив", но $sort
в рамката за агрегиране винаги е използвал "първата позиция" на масива, за да сортира съдържанието. Това означава, че с единична стойност, извлечена от индексираната позиция (точно както дългата процедура по-горе), тогава резултатът ще бъде сортиран, както очаквате.
Крайните случаи тук са точно така. Или живейте с типа операции, от които се нуждаете отгоре, за да работите с индексирана позиция на масива, или „изчакайте“, докато чисто нова лъскава версия ви дойде на помощ с по-добри оператори.