Pregunta Cómo obtener el ranking del artículo en la lista ordenada por múltiples campos en Mongoose


Tengo un número de registros de usuarios (> 10000) en una colección de MongoDB que se pueden ordenar por puntuación desc + tiempo asc + bonificación desc. ¿Cómo puedo obtener la clasificación de un usuario en la lista de acuerdo con esta clasificación utilizando Mongoose? Supongamos que el índice se ha construido correctamente.


5
2018-04-10 09:22


origen


Respuestas:


Cuente el número de usuarios que vienen antes de este usuario en su orden de clasificación. Comenzaré con el caso de una ordenación simple (no compuesta) porque la consulta en el caso compuesto es más complicada, aunque la idea sea exactamente la misma.

> db.test.drop()
> for (var i = 0; i < 10; i++) db.test.insert({ "x" : i })
> db.test.find({ }, { "_id" : 0 }).sort({ "x" : -1 }).limit(5)
{ "x" : 9 }
{ "x" : 8 }
{ "x" : 7 }
{ "x" : 6 }
{ "x" : 5 }

Para este orden, la clasificación de un documento { "x" : i } es el numero de documentos { "x" : j } con i < j

> var rank = function(id) {
    var i = db.test.findOne({ "_id" : id }).x
    return db.test.count({ "x" : { "$gt" : i } })
}
> var id = db.test.findOne({ "x" : 5 }).id
> rank(id)
4

La clasificación se basará en 0. Del mismo modo, si desea calcular la clasificación para el documento { "x" : i } en el género { "x" : 1 }, contarías la cantidad de documentos { "x" : j } con i > j.

Para una clasificación compuesta, el mismo procedimiento funciona, pero es más difícil de implementar porque el orden en un índice compuesto es lexicográfico, es decir, para la clasificación { "a" : 1, "b" : 1}, (a, b) < (c, d) Si a < c o a = c y b < d, entonces necesitamos una consulta más complicada para expresar esta condición. Aquí hay un ejemplo para un índice compuesto:

> db.test.drop()
> for (var i = 0; i < 3; i++) {
    for (var j = 0; j < 3; j++) {
        db.test.insert({ "x" : i, "y" : j })
    }
}
> db.test.find({}, { "_id" : 0 }).sort({ "x" : 1, "y" : -1 })
{ "x" : 0, "y" : 2 }
{ "x" : 0, "y" : 1 }
{ "x" : 0, "y" : 0 }
{ "x" : 1, "y" : 2 }
{ "x" : 1, "y" : 1 }
{ "x" : 1, "y" : 0 }
{ "x" : 2, "y" : 2 }
{ "x" : 2, "y" : 1 }
{ "x" : 2, "y" : 0 }

Para encontrar el rango para el documento { "x" : i, "y" : j }, necesitas encontrar el número de documentos { "x" : a, "y" : b } en el orden { "x" : 1, "y" : -1 } tal que (i, j) < (a, b). Dada la especificación de clasificación, esto es equivalente a la condición i < a o i = a y j > b:

> var rank = function(id) {
    var doc = db.test.findOne(id)
    var i = doc.x
    var j = doc.y
    return db.test.count({
        "$or" : [
            { "x" : { "$lt" : i } },
            { "x" : i, "y" : { "$gt" : j } }
        ]
    })
}
> id = db.test.findOne({ "x" : 1, "y" : 1 })._id
> rank(id)
4

Finalmente, en su caso de un índice compuesto de tres partes

{ "score" : -1, "time" : 1, "bonus" : -1 }

el rank la función sería

> var rank = function(id) {
    var doc = db.test.findOne(id)
    var score = doc.score
    var time = doc.time
    var bonus = doc.bonus
    return db.test.count({
        "$or" : [
            { "score" : { "$gt" : score } },
            { "score" : score, "time" : { "$lt" : time } },
            { "score" : score, "time" : time, "bonus" : { "$gt" : bonus } }
        ]
    })
}

10
2018-04-10 15:35