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

Cómo obtener la clasificación de elementos en la lista ordenada por múltiples campos en Mongoose

Cuente la cantidad de usuarios que vienen antes que este usuario en su orden de clasificación. Comenzaré con el caso de un tipo simple (no compuesto) porque la consulta en el caso compuesto es más complicada, aunque la idea es 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 pedido, la clasificación de un documento { "x" : i } es el número 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. De manera similar, si desea calcular la clasificación para el documento { "x" : i } en el tipo { "x" : 1 } , contaría la cantidad de documentos { "x" : j } con i > j .

Para una ordenación compuesta, funciona el mismo procedimiento, pero es más complicado de implementar porque el orden en un índice compuesto es lexicográfico, es decir, para la ordenación { "a" : 1, "b" : 1} , (a, b) < (c, d) si a < c o a = c y b < d , por lo que necesitamos una consulta más complicada para expresar esta condición. He aquí un ejemplo de 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 del documento { "x" : i, "y" : j } , necesita 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 } }
        ]
    })
}