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

Comment trier par 'valeur' ​​d'une clé spécifique dans une propriété stockée sous forme de tableau avec des paires k-v dans mongodb

En supposant que ce que vous voulez serait tous les documents qui ont la valeur "points" comme "clé" dans le tableau, puis triez sur la "valeur" pour cette "clé", alors c'est un peu hors de portée pour le .find() méthode.

Raison d'être si vous faisiez quelque chose comme ça

db.collection.find({
    "setid": 154421, "data.k": "point" }
).sort({ "data.v" : -1 })

Le problème est que même si les éléments correspondants font ont la clé correspondante de "point", il n'y a aucun moyen de dire quel data.v vous faites référence au tri. Aussi, un sort dans .find() les résultats ne feront pas quelque chose comme ça :

db.collection.find({
    "setid": 154421, "data.k": "point" }
).sort({ "data.$.v" : -1 })

Ce qui serait essayer pour utiliser un opérateur positionnel dans un tri, indiquant essentiellement quel élément utiliser la valeur de v sur. Mais cela n'est pas pris en charge et ne le sera probablement pas, et pour l'explication la plus probable, cette valeur "d'index" serait probablement différente dans chaque document.

Mais ce genre de sélectif le tri peut être fait avec l'utilisation de .aggregate() .

db.collection.aggregate([

    // Actually shouldn't need the setid
    { "$match": { "data": {"$elemMatch": { "k": "points" } } } },

    // Saving the original document before you filter
    { "$project": {
        "doc": {
           "_id": "$_id",
           "setid": "$setid",
           "date": "$date",
           "version": "$version",
           "data": "$data"
        },
        "data": "$data"
    }}

    // Unwind the array
    { "$unwind": "$data" },

    // Match the "points" entries, so filtering to only these
    { "$match": { "data.k": "points" } },

    // Sort on the value, presuming you want the highest
    { "$sort": { "data.v": -1 } },

    // Restore the document
    { "$project": {
        "setid": "$doc.setid",
        "date": "$doc.date",
        "version": "$doc.version",
        "data": "$doc.data"
    }} 

])

Bien sûr, cela suppose les data le tableau n'a que un élément qui a les points clés. S'il y en avait plus d'un, vous auriez besoin de $group avant le tri comme ceci :

    // Group to remove the duplicates and get highest
    { "$group": { 
        "_id": "$doc",
        "value": { "$max": "$data.v" }
    }},

    // Sort on the value
    { "$sort": { "value": -1 } },

    // Restore the document
    { "$project": { 
        "_id": "$_id._id",
        "setid": "$_id.setid",
        "date": "$_id.date",
        "version": "$_id.version",
        "data": "$_id.data"
    }}

Il y a donc une utilisation de .aggregate() afin de faire du complexe trier les documents tout en renvoyant le résultat du document d'origine dans son intégralité.

Lisez un peu plus sur les opérateurs d'agrégation et le cadre général. C'est un outil utile pour apprendre qui vous emmène au-delà de .find() .