sql >> Base de Datos >  >> NoSQL >> MongoDB

Clasificación por campo de matriz máximo, ascendente o descendente

El problema básico con lo que está preguntando aquí se reduce al hecho de que los datos en cuestión están dentro de una "matriz" y, por lo tanto, MongoDB hace algunas suposiciones básicas sobre cómo se maneja esto.

Si aplicó una ordenación en "orden descendente", entonces MongoDB hará exactamente lo que le pide y ordenará los documentos por el valor "mayor" del campo especificado dentro de la matriz:

.sort({ "revisions.created": -1 ))

Pero si, en cambio, ordena en orden "ascendente", entonces, por supuesto, lo contrario es cierto y se considera el valor "más pequeño".

.sort({ "revisions.created": 1 })

Entonces, la única forma de hacer esto es calcular cuál es la fecha máxima de los datos en la matriz y luego ordenar ese resultado. Básicamente, esto significa aplicar .aggregate() , que para Meteor es una operación del lado del servidor, siendo lamentablemente algo como esto:

Collection.aggregate([
    { "$unwind": "$revisions" },
    { "$group": {
        "_id": "$_id",
        "name": { "$first": "$name" },
        "revisions": { "$push": "$revisions" },
        "number": { "$first": "$number" }
        "maxDate": { "$max": "$revisions.created" }
    }},
    { "$sort": { "maxDate": 1 }
])

O en el mejor de los casos con MongoDB 3.2, donde $max se puede aplicar directamente a una expresión de matriz:

Collection.aggregate([
    { "$project": {
        "name": 1,
        "revisions": 1,
        "number": 1,
        "maxDate": {
            "$max": {
                "$map": {
                    "input": "$revisions",
                    "as": "el",
                    "in": "$$el.created"
                }
            }
        }
    }},
    { "$sort": { "maxDate": 1 } }
])

Pero en realidad ninguno de los dos es tan bueno, incluso si el enfoque de MongoDB 3.2 tiene una sobrecarga mucho menor que la que está disponible para las versiones anteriores, todavía no es tan bueno como se puede obtener en términos de rendimiento debido a la necesidad de pasar los datos y el trabajo. a cabo el valor para ordenar.

Entonces, para mejor rendimiento, "siempre" mantenga los datos que necesitará "fuera" de la matriz. Para esto existe el $max Operador "actualizar", que solo reemplazará un valor dentro del documento "si" el valor proporcionado es "mayor que" el valor existente que ya existe. es decir:

Collection.update(
    { "_id": "qTF8kEphNoB3eTNRA" },
    { 
        "$push": {
            "revisions": { "created": new Date("2016-02-01") }            
        },
        "$max": { "maxDate": new Date("2016-02-01") }
    }
)

Esto significa que el valor que desea "siempre" ya estará presente en el documento con el valor esperado, por lo que ahora es una simple cuestión de ordenar en ese campo:

.sort({ "maxDate": 1 })

Entonces, por mi dinero, revisaría los datos existentes con cualquiera de los .aggregate() declaraciones disponibles, y use esos resultados para actualizar cada documento para que contenga un campo "maxDate". Luego cambie la codificación de todas las adiciones y revisiones de los datos de matriz para aplicar ese $max "actualizar" en cada cambio.

Tener un campo sólido en lugar de un cálculo siempre tiene mucho más sentido si lo usa con la suficiente frecuencia. Y el mantenimiento es bastante sencillo.

En cualquier caso, considerando la fecha del ejemplo aplicado anteriormente, que es "menor que" las otras fechas máximas presentes, me devolvería en todas las 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")
}

Lo que coloca correctamente el primer documento en la parte superior del orden de clasificación teniendo en cuenta la "fecha máxima".