MongoDB
 sql >> Database >  >> NoSQL >> MongoDB

Come ordinare per "valore" di una chiave specifica all'interno di una proprietà archiviata come matrice con coppie k-v in mongodb

Supponendo che quello che vuoi siano tutti i documenti che hanno il valore "punti" come "chiave" nell'array, e quindi ordina in base al "valore" per quella "chiave", allora questo è un po' fuori dall'ambito del .find() metodo.

Il motivo è se hai fatto qualcosa del genere

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

Il problema è che anche se gli elementi abbinati fanno hanno la chiave di corrispondenza di "punto", non c'è modo di dire quale data.v ti riferisci all'ordinamento. Inoltre, un sort all'interno di .find() i risultati non funzioneranno in questo modo:

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

Il che sarebbe provare utilizzare un operatore posizionale all'interno di un ordinamento, indicando essenzialmente quale elemento utilizzare il valore di v Su. Ma questo non è supportato e probabilmente non lo sarà, e per la spiegazione più probabile, quel valore "indice" sarebbe probabilmente diverso in ogni documento.

Ma questo tipo di selettivo l'ordinamento può essere eseguito utilizzando .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"
    }} 

])

Ovviamente ciò presuppone i data array ha solo uno elemento che ha i punti chiave. Se ce ne fosse più di uno, dovresti $group prima dell'ordinamento in questo modo:

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

Quindi esiste un utilizzo di .aggregate() per fare alcuni complessi l'ordinamento sui documenti e restituire comunque il risultato del documento originale per intero.

Approfondisci gli operatori di aggregazione e il quadro generale. È uno strumento utile per imparare che ti porta oltre .find() .