Comptez le nombre d'utilisateurs qui précèdent cet utilisateur dans votre ordre de tri. Je vais commencer par le cas d'un tri simple (tri non composé) car la requête dans le cas composé est plus compliquée, même si l'idée est exactement la même.
> 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 }
Pour cette commande, le classement d'un document { "x" : i }
est le nombre de documents { "x" : j }
avec 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
Le classement sera basé sur 0. De même, si vous souhaitez calculer le classement du document { "x" : i }
dans le tri { "x" : 1 }
, vous compteriez le nombre de docs { "x" : j }
avec i > j
.
Pour un tri composé, la même procédure fonctionne, mais elle est plus délicate à mettre en œuvre car l'ordre dans un index composé est lexicographique, c'est-à-dire pour le tri { "a" : 1, "b" : 1}
, (a, b) < (c, d)
si a < c
ou a = c
et b < d
, nous avons donc besoin d'une requête plus compliquée pour exprimer cette condition. Voici un exemple d'index composé :
> 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 }
Pour trouver le rang du document { "x" : i, "y" : j }
, vous devez trouver le nombre de documents { "x" : a, "y" : b }
dans l'ordre { "x" : 1, "y" : -1 }
tel que (i, j) < (a, b)
. Compte tenu de la spécification de tri, cela équivaut à la condition i < a
ou i = a
et 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
Enfin, dans votre cas d'un index composé en trois parties
{ "score" : -1, "time" : 1, "bonus" : -1 }
le rank
fonction serait
> 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 } }
]
})
}