sql >> Database >  >> NoSQL >> MongoDB

Sorteren op 'waarde' van een specifieke sleutel binnen een eigenschap die is opgeslagen als een array met k-v-paren in mongodb

Ervan uitgaande dat wat u wilt alle documenten zijn die de "punten"-waarde als een "sleutel" in de array hebben, en dan sorteren op de "waarde" voor die "sleutel", dan is dit een beetje buiten het bereik van de .find() methode.

Reden hiervoor is dat je zoiets hebt gedaan

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

Het probleem is dat ook al de overeenkomende elementen doen de overeenkomende sleutel van "point" hebben, is er geen manier om welke . te vertellen data.v je verwijst naar de soort. Ook een sort binnen .find() resultaten doen niet zoiets als dit:

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

Wat zou zijn proberen om een ​​positionele operator binnen een sort te gebruiken, in wezen vertellend welk element de waarde van v . moet gebruiken Aan. Maar dit wordt niet ondersteund en het is niet waarschijnlijk, en voor de meest waarschijnlijke verklaring, die "index" -waarde zou waarschijnlijk in elk document anders zijn.

Maar dit soort selectieve sorteren kan met behulp van .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"
    }} 

])

Dat veronderstelt natuurlijk de data array heeft alleen de één element met de belangrijkste punten. Als er meer dan één waren, moet u $group voor het soort als volgt:

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

Er is dus één gebruik van .aggregate() om wat complexe te doen sorteren op documenten en toch het originele documentresultaat volledig retourneren.

Lees meer over aggregatie-operators en het algemene kader. Het is een handig hulpmiddel om te leren dat je verder brengt dan .find() .




  1. Partitioneer gegevens rond een matchquery tijdens aggregatie

  2. Mongo-fout op I control hotfix

  3. php mongodb zoeken en sorteren in volledige tekst

  4. Hoe toegang te krijgen tot geneste bestanden met Pick<> typoscript