MongoDB
 sql >> Base de Dados >  >> NoSQL >> MongoDB

Classificando por campo de array máximo, crescente ou decrescente


O problema básico com o que você está perguntando aqui se resume ao fato de que os dados em questão estão dentro de um "array" e, portanto, existem algumas suposições básicas feitas pelo MongoDB sobre como isso é tratado.

Se você aplicou uma classificação em "ordem decrescente", o MongoDB fará exatamente o que você pedir e classificará os documentos pelo valor "maior" do campo especificado na matriz:
.sort({ "revisions.created": -1 ))

Mas se, em vez disso, você classificar em ordem "crescente", é claro que o inverso é verdadeiro e o valor "menor" é considerado.
.sort({ "revisions.created": 1 })

Portanto, a única maneira de fazer isso significa descobrir qual é a data máxima dos dados na matriz e, em seguida, classificar esse resultado. Isso basicamente significa aplicar .aggregate() , que para meteoro é uma operação do lado do servidor, sendo infelizmente algo assim:
Collection.aggregate([
    { "$unwind": "$revisions" },
    { "$group": {
        "_id": "$_id",
        "name": { "$first": "$name" },
        "revisions": { "$push": "$revisions" },
        "number": { "$first": "$number" }
        "maxDate": { "$max": "$revisions.created" }
    }},
    { "$sort": { "maxDate": 1 }
])

Ou na melhor das hipóteses com o MongoDB 3.2, onde $max pode ser aplicado diretamente a uma expressão de matriz:
Collection.aggregate([
    { "$project": {
        "name": 1,
        "revisions": 1,
        "number": 1,
        "maxDate": {
            "$max": {
                "$map": {
                    "input": "$revisions",
                    "as": "el",
                    "in": "$$el.created"
                }
            }
        }
    }},
    { "$sort": { "maxDate": 1 } }
])

Mas realmente ambos não são tão bons, mesmo que a abordagem do MongoDB 3.2 tenha muito menos sobrecarga do que o disponível nas versões anteriores, ainda não é tão bom quanto você pode obter em termos de desempenho devido à necessidade de passar pelos dados e trabalhar o valor para classificar.

Então, para melhor desempenho, "sempre" mantenha esses dados que você vai precisar "fora" do array. Para isso existe o $max operador "update", que só substituirá um valor dentro do documento "se" o valor fornecido for "maior que" o valor existente já existente. ou seja:
Collection.update(
    { "_id": "qTF8kEphNoB3eTNRA" },
    { 
        "$push": {
            "revisions": { "created": new Date("2016-02-01") }            
        },
        "$max": { "maxDate": new Date("2016-02-01") }
    }
)

Isso significa que o valor que você deseja "sempre" já estará presente no documento com o valor esperado, então agora é uma simples questão de classificar nesse campo:
.sort({ "maxDate": 1 })

Então, pelo meu dinheiro, eu iria pelos dados existentes com um dos .aggregate() instruções disponíveis e use esses resultados para atualizar cada documento para conter um campo "maxDate". Em seguida, altere a codificação de todas as adições e revisões de dados de matriz para aplicar esse $max "atualizar" a cada mudança.

Ter um campo sólido em vez de um cálculo sempre faz muito mais sentido se você o estiver usando com bastante frequência. E a manutenção é bem simples.

De qualquer forma, considerando a data de exemplo aplicada acima, que é "menor que" as outras datas máximas presentes retornariam para mim em todas as formas:
{
        "_id" : "5xF9iDTj3reLDKNHh",
        "name" : "Lorem ipsum",
        "revisions" : [
                {
                        "number" : 0,
                        "comment" : "Dolor sit amet",
                        "created" : ISODate("2016-02-11T01:22:45.588Z")
                }
        ],
        "number" : 1,
        "maxDate" : ISODate("2016-02-11T01:22:45.588Z")
}
{
        "_id" : "qTF8kEphNoB3eTNRA",
        "name" : "Consecitur quinam",
        "revisions" : [
                {
                        "comment" : "Hoste ad poderiquem",
                        "number" : 1,
                        "created" : ISODate("2016-02-11T23:25:46.033Z")
                },
                {
                        "number" : 0,
                        "comment" : "Fagor questibilus",
                        "created" : ISODate("2016-02-11T01:22:45.588Z")
                },
                {
                        "created" : ISODate("2016-02-01T00:00:00Z")
                }
        ],
        "number" : 2,
        "maxDate" : ISODate("2016-02-11T23:25:46.033Z")
}

O que coloca corretamente o primeiro documento no topo da ordem de classificação, considerando a "maxDate".