Kerangka kerja agregasi tidak "menangani" array dengan cara yang sama seperti yang diterapkan pada .find()
query secara umum. Ini tidak hanya berlaku untuk operasi seperti .sort()
, tetapi juga dengan operator lain, yaitu $slice
, meskipun contoh tersebut akan segera diperbaiki ( lebih lanjut nanti ).
Jadi hampir tidak mungkin untuk menangani apa pun menggunakan formulir "notasi titik" dengan indeks posisi array seperti yang Anda miliki. Tapi ada cara untuk mengatasi ini.
Apa yang Anda "bisa" lakukan pada dasarnya adalah mencari tahu apa sebenarnya elemen array "n" sebagai nilai, dan kemudian mengembalikannya sebagai bidang yang dapat diurutkan:
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 } }
])
Ini adalah pendekatan yang mengerikan dan "dapat diubah" di mana Anda pada dasarnya "melangkah melalui" setiap elemen array dengan mendapatkan $first
cocok per dokumen dari larik setelah diproses dengan $unwind
. Kemudian setelah $unwind
lagi, Anda menguji untuk melihat apakah elemen larik itu sama dengan yang sudah "dilihat" dari posisi larik yang diidentifikasi.
Ini mengerikan, dan lebih buruk lagi untuk lebih banyak posisi yang ingin Anda pindahkan, tetapi hasilnya akan didapat:
{ "_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 }
Untungnya, rilis MongoDB yang akan datang (seperti yang saat ini tersedia dalam rilis pengembangan) mendapatkan "perbaikan" untuk ini. Ini mungkin bukan perbaikan "sempurna" yang Anda inginkan, tetapi ini memecahkan masalah dasar.
Ada $slice
baru operator tersedia untuk kerangka kerja agregasi di sana, dan ia akan mengembalikan elemen larik yang diperlukan dari posisi yang diindeks:
db.test.aggregate([
{ "$project": {
"items": 1,
"slice": { "$slice": [ "$items",1,1 ] }
}},
{ "$sort": { "slice": -1 } }
])
Yang menghasilkan:
{ "_id" : 2, "items" : [ 0, 3, 4 ], "slice" : [ 3 ] }
{ "_id" : 1, "items" : [ 1, 2, 0 ], "slice" : [ 2 ] }
{ "_id" : 3, "items" : [ 2, 1, 5 ], "slice" : [ 1 ] }
Jadi Anda dapat mencatat bahwa sebagai "slice", hasilnya masih berupa "array", namun $sort
dalam kerangka agregasi selalu menggunakan "posisi pertama" dari array untuk mengurutkan konten. Artinya dengan nilai singular yang diekstrak dari posisi terindeks (seperti prosedur panjang di atas) maka hasilnya akan diurutkan seperti yang Anda harapkan.
Kasus akhir di sini adalah begitulah cara kerjanya. Baik hidup dengan jenis operasi yang Anda perlukan dari atas untuk bekerja dengan posisi array yang diindeks, atau "tunggu" hingga versi baru yang mengkilap datang untuk menyelamatkan Anda dengan operator yang lebih baik.