MongoDB
 sql >> Datenbank >  >> NoSQL >> MongoDB

So sortieren Sie nach „Wert“ eines bestimmten Schlüssels innerhalb einer Eigenschaft, die als Array mit k-v-Paaren in Mongodb gespeichert ist

Angenommen, Sie möchten alle Dokumente, die den Wert "Punkte" als "Schlüssel" im Array haben, und dann nach dem "Wert" für diesen "Schlüssel" sortieren, dann ist dies etwas außerhalb des Bereichs für die .find() Methode.

Der Grund dafür ist, wenn Sie so etwas getan haben

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

Das Problem ist, dass obwohl die übereinstimmenden Elemente tun den passenden Schlüssel von "Punkt" haben, gibt es keine Möglichkeit zu sagen, welcher data.v Sie beziehen sich auf die Sorte. Auch eine sort innerhalb von .find() Ergebnisse werden so etwas nicht tun:

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

Was versuchen wäre um einen Positionsoperator innerhalb einer Sortierung zu verwenden, der im Wesentlichen angibt, welches Element den Wert von v verwenden soll an. Aber dies wird nicht unterstützt und wird es wahrscheinlich auch nicht sein, und für die wahrscheinlichste Erklärung wäre dieser "Index"-Wert wahrscheinlich in jedem Dokument unterschiedlich.

Aber diese Art von selektiv die Sortierung kann mithilfe von .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"
    }} 

])

Das setzt natürlich die data voraus array hat nur die eine Element, das die wichtigsten Punkte hat. Wenn es mehr als eine gäbe, müssten Sie $group vor der Sortierung so:

    // 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"
    }}

Es gibt also eine Verwendung von .aggregate() um etwas komplex zu machen nach Dokumenten sortieren und trotzdem das ursprüngliche Dokumentergebnis vollständig zurückgeben.

Lesen Sie mehr über Aggregationsoperatoren und die allgemeinen Rahmenbedingungen. Es ist ein nützliches Werkzeug zum Lernen, das Sie über .find() hinausführt .