Il framework di aggregazione semplicemente non "gestisce" gli array nello stesso modo in cui viene applicato a .find()
interrogazioni in generale. Questo non vale solo per operazioni come .sort()
, ma anche con altri operatori, e precisamente $slice
, anche se l'esempio sta per ottenere una correzione (più avanti).
Quindi è praticamente impossibile gestire qualsiasi cosa usando il modulo "notazione punto" con un indice di una posizione di matrice come hai tu. Ma c'è un modo per aggirare questo problema.
Quello che "puoi" fare è fondamentalmente capire cosa sia effettivamente l'elemento dell'array "nesimo" come valore, e quindi restituirlo come un campo che può essere ordinato:
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 } }
])
È un approccio orribile e "iterabile" in cui essenzialmente "passi attraverso" ogni elemento dell'array ottenendo il $first
corrispondenza per documento dall'array dopo l'elaborazione con $unwind
. Quindi dopo $unwind
di nuovo, provi per vedere se quegli elementi dell'array sono gli stessi di quelli già "visti" dalle posizioni dell'array identificate.
È terribile, e peggio per le posizioni in cui vuoi muoverti, ma ottiene il risultato:
{ "_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 }
Fortunatamente, le prossime versioni di MongoDB (come attualmente disponibili nelle versioni di sviluppo) ottengono una "correzione" per questo. Potrebbe non essere la soluzione "perfetta" che desideri, ma risolve il problema di base.
C'è una nuova $slice
operatore disponibile per il framework di aggregazione lì e restituirà gli elementi richiesti dell'array dalle posizioni indicizzate:
db.test.aggregate([
{ "$project": {
"items": 1,
"slice": { "$slice": [ "$items",1,1 ] }
}},
{ "$sort": { "slice": -1 } }
])
Che produce:
{ "_id" : 2, "items" : [ 0, 3, 4 ], "slice" : [ 3 ] }
{ "_id" : 1, "items" : [ 1, 2, 0 ], "slice" : [ 2 ] }
{ "_id" : 3, "items" : [ 2, 1, 5 ], "slice" : [ 1 ] }
Quindi puoi notare che come "fetta", il risultato è ancora un "array", tuttavia il $sort
nel framework di aggregazione ha sempre utilizzato la "prima posizione" dell'array per ordinare i contenuti. Ciò significa che con un valore singolare estratto dalla posizione indicizzata (proprio come la procedura lunga sopra) il risultato verrà ordinato come previsto.
I casi finali qui sono che è proprio come funziona. O vivi con il tipo di operazioni di cui hai bisogno dall'alto per lavorare con una posizione indicizzata dell'array, o "aspetta" fino a quando una nuova versione brillante viene in tuo soccorso con operatori migliori.