sql >> Base de Datos >  >> NoSQL >> MongoDB

Cómo ordenar por 'valor' de una clave específica dentro de una propiedad almacenada como una matriz con pares k-v en mongodb

Suponiendo que lo que desea serían todos los documentos que tienen el valor de "puntos" como una "clave" en la matriz, y luego ordena el "valor" para esa "clave", entonces esto está un poco fuera del alcance de la .find() método.

La razón es si hiciste algo como esto

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

El problema es que aunque los elementos coincidentes do tiene la clave coincidente de "punto", no hay forma de decir cuál data.v te refieres al tipo. Además, un sort dentro de .find() los resultados no harán algo como esto:

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

¿Cuál sería intentar para usar un operador posicional dentro de una ordenación, esencialmente diciendo qué elemento usar el valor de v en. Pero esto no es compatible y no es probable que lo sea, y para la explicación más probable, ese valor de "índice" probablemente sea diferente en cada documento.

Pero este tipo de selectivo la clasificación se puede realizar con el uso 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"
    }} 

])

Por supuesto, eso supone los data matriz solo tiene el uno elemento que tiene los puntos clave. Si hubiera más de uno, necesitaría $group antes de la ordenación como esta:

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

Entonces hay un uso de .aggregate() para hacer algo complejo clasificar los documentos y devolver el resultado del documento original en su totalidad.

Lea un poco más sobre operadores de agregación y el marco general. Es una herramienta útil para aprender que lo lleva más allá de .find() .