A estrutura de agregação simplesmente não "lida com" arrays da mesma forma que é aplicada a
.find()
consultas em geral. Isso não é verdade apenas para operações como .sort()
, mas também com outros operadores, nomeadamente $slice
, embora esse exemplo esteja prestes a receber uma correção ( mais tarde ). Portanto, é praticamente impossível lidar com qualquer coisa usando a forma de "notação de ponto" com um índice de uma posição de matriz como você tem. Mas há uma maneira de contornar isso.
O que você "pode" fazer é basicamente descobrir o que o elemento de matriz "nth" realmente é como um valor e, em seguida, retornar isso como um campo que pode ser classificado:
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 } }
])
É uma abordagem horrível e "iterável" onde você essencialmente "percorre" cada elemento da matriz obtendo o
$first
corresponda por documento da matriz após o processamento com $ descontrair
. Depois de $unwind
novamente, você testa para ver se os elementos do array são os mesmos que já foram "vistos" das posições do array identificadas. É terrível e pior para mais posições que você deseja avançar, mas obtém o resultado:
{ "_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 }
Felizmente, os próximos lançamentos do MongoDB (como atualmente disponível em lançamentos de desenvolvimento) recebem uma "correção" para isso. Pode não ser a correção "perfeita" que você deseja, mas resolve o problema básico.
Há um novo
$slice
operador disponível para a estrutura de agregação lá, e retornará o(s) elemento(s) necessário(s) da matriz das posições indexadas: db.test.aggregate([
{ "$project": {
"items": 1,
"slice": { "$slice": [ "$items",1,1 ] }
}},
{ "$sort": { "slice": -1 } }
])
Que produz:
{ "_id" : 2, "items" : [ 0, 3, 4 ], "slice" : [ 3 ] }
{ "_id" : 1, "items" : [ 1, 2, 0 ], "slice" : [ 2 ] }
{ "_id" : 3, "items" : [ 2, 1, 5 ], "slice" : [ 1 ] }
Então você pode notar que como uma "fatia", o resultado ainda é um "array", porém o
$sort
na estrutura de agregação sempre usou a "primeira posição" da matriz para classificar o conteúdo. Isso significa que com um valor singular extraído da posição indexada ( assim como o procedimento longo acima ), o resultado será classificado como você espera. Os casos finais aqui são exatamente assim que funciona. Ou viva com o tipo de operações que você precisa de cima para trabalhar com uma posição indexada da matriz ou "espere" até que uma nova versão brilhante venha em seu socorro com operadores melhores.