sql >> Databasteknik >  >> NoSQL >> MongoDB

Hur man sorterar efter "värde" för en specifik nyckel inom en egenskap lagrad som en array med k-v-par i mongodb

Om du antar att det du vill ha är alla dokument som har "points"-värdet som en "nyckel" i arrayen och sedan sorterar på "värdet" för den "nyckeln", så är detta lite utanför räckvidden för .find() metod.

Anledningen är att du gjorde något liknande

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

Problemet är att även om de matchade elementen gör har den matchande nyckeln "punkt", det finns inget sätt att säga vilken data.v du syftar på för den sorten. Dessutom en sort inom .find() resultat kommer inte att göra något så här:

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

Vilket skulle vara försöker att använda en positionsoperator inom en sortering, som i huvudsak talar om vilket element som ska använda värdet på v på. Men detta stöds inte och kommer sannolikt inte att vara, och för den mest troliga förklaringen, skulle det "index"-värdet troligen vara olika i varje dokument.

Men den här typen av selektiv sortering kan göras med hjälp av .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"
    }} 

])

Det förutsätter naturligtvis data arrayen har bara en element som har nyckelpunkterna. Om det fanns mer än en, skulle du behöva $group före sorten så här:

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

Så det finns en användning av .aggregate() för att göra något komplicerat sortera på dokument och ändå returnera originaldokumentets resultat i sin helhet.

Läs mer om aggregationsoperatorer och den allmänna ramen. Det är ett användbart verktyg att lära sig som tar dig bortom .find() .




  1. Skicka typinformation till MongoDB så att den kan deserialisera gränssnittstyper ordentligt?

  2. kommandomarkörens objekt kan inte tecknas

  3. mongodb groupby långsam även efter att ha lagt till index

  4. Enkel Node/Express-app, det funktionella programmeringssättet (Hur hanterar man biverkningar i JavaScript?)