MongoDB
 sql >> Base de données >  >> NoSQL >> MongoDB

Tri par champ de tableau maximum, croissant ou décroissant

Le problème fondamental avec ce que vous demandez ici se résume au fait que les données en question se trouvent dans un "tableau", et donc il y a des hypothèses de base faites par MongoDB quant à la façon dont cela est géré.

Si vous avez appliqué un tri en "ordre décroissant", alors MongoDB fera exactement ce que vous demandez et triera les documents par la "plus grande" valeur du champ spécifié dans le tableau :

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

Mais si à la place vous triez dans l'ordre "ascendant", alors bien sûr l'inverse est vrai et la "plus petite" valeur est prise en compte.

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

Ainsi, la seule façon de procéder consiste à déterminer quelle est la date maximale à partir des données du tableau, puis à trier sur ce résultat. Cela signifie essentiellement l'application de .aggregate() , qui pour meteor est une opération côté serveur, étant malheureusement quelque chose comme ça :

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

Ou au mieux avec MongoDB 3.2, où $max peut être appliqué directement à une expression tableau :

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

Mais vraiment les deux ne sont pas si géniaux, même si l'approche MongoDB 3.2 a beaucoup moins de frais généraux que ce qui est disponible dans les versions précédentes, ce n'est toujours pas aussi bon que vous pouvez obtenir en termes de performances en raison de la nécessité de passer par les données et de travailler la valeur à trier.

Donc, pour le meilleur performances, conservez "toujours" les données dont vous aurez besoin "en dehors" de la baie. Pour cela il y a le $max Opérateur "mise à jour", qui ne remplacera une valeur dans le document que "si" la valeur fournie est "supérieure à" la valeur existante déjà présente. c'est-à-dire :

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

Cela signifie que la valeur que vous voulez sera "toujours" déjà présente dans le document avec la valeur attendue, donc c'est juste maintenant une simple question de tri sur ce champ :

.sort({ "maxDate": 1 })

Donc, pour mon argent, j'irais dans les données existantes avec l'un des .aggregate() instructions disponibles et utilisez ces résultats pour mettre à jour chaque document afin qu'il contienne un champ "maxDate". Modifiez ensuite le codage de tous les ajouts et révisions des données du tableau pour appliquer ce $max "mettre à jour" à chaque changement.

Avoir un champ solide plutôt qu'un calcul a toujours beaucoup plus de sens si vous l'utilisez assez souvent. Et l'entretien est assez simple.

Dans tous les cas, compte tenu de l'exemple de date appliqué ci-dessus, qui est "inférieur à" les autres dates maximales présentes me reviendraient sous toutes les formes :

{
        "_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")
}

Ce qui place correctement le premier document en haut de l'ordre de tri en tenant compte de la "maxDate".