Hitung jumlah pengguna yang datang sebelum pengguna ini dalam urutan pengurutan Anda. Saya akan mulai dengan kasus sederhana (non-compound sort) karena kueri dalam kasus majemuk lebih rumit, meskipun idenya persis sama.
> 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 }
Untuk urutan ini, peringkat dokumen { "x" : i }
adalah jumlah dokumen { "x" : j }
dengan 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
Pemeringkatan akan didasarkan pada 0. Demikian pula, jika Anda ingin menghitung peringkat untuk dokumen { "x" : i }
di sort { "x" : 1 }
, Anda akan menghitung jumlah dokumen { "x" : j }
dengan i > j
.
Untuk pengurutan majemuk, prosedur yang sama bekerja, tetapi lebih sulit untuk diterapkan karena urutan dalam indeks majemuk adalah leksikografis, yaitu untuk pengurutan { "a" : 1, "b" : 1}
, (a, b) < (c, d)
jika a < c
atau a = c
dan b < d
, jadi kita membutuhkan query yang lebih rumit untuk mengekspresikan kondisi ini. Berikut ini contoh untuk indeks gabungan:
> 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 }
Untuk mencari peringkat dokumen { "x" : i, "y" : j }
, Anda perlu menemukan jumlah dokumen { "x" : a, "y" : b }
dalam urutan { "x" : 1, "y" : -1 }
sedemikian rupa sehingga (i, j) < (a, b)
. Mengingat spesifikasi pengurutan, ini setara dengan kondisi i < a
atau i = a
dan 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
Terakhir, dalam kasus Anda tentang indeks gabungan tiga bagian
{ "score" : -1, "time" : 1, "bonus" : -1 }
rank
fungsinya adalah
> 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 } }
]
})
}