MongoDB
 sql >> Database >  >> NoSQL >> MongoDB

Come ottenere la classifica degli articoli nell'elenco ordinato per più campi in Mongoose

Conta il numero di utenti che precedono questo utente nel tuo ordinamento. Inizierò con il caso di un ordinamento semplice (non composto) perché la query nel caso composto è più complicata, anche se l'idea è esattamente la stessa.

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

Per questo ordine, la classifica di un documento { "x" : i } è il numero di documenti { "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 classifica sarà basata su 0. Allo stesso modo, se vuoi calcolare la classifica per il documento { "x" : i } nell'ordinamento { "x" : 1 } , dovresti contare il numero di documenti { "x" : j } con i > j .

Per un ordinamento composto, la stessa procedura funziona, ma è più complicata da implementare perché l'ordine in un indice composto è lessicografico, cioè per l'ordinamento { "a" : 1, "b" : 1} , (a, b) < (c, d) se a < c o a = c e b < d , quindi abbiamo bisogno di una query più complicata per esprimere questa condizione. Ecco un esempio per un indice composto:

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

Per trovare la classifica per il documento { "x" : i, "y" : j } , devi trovare il numero di documenti { "x" : a, "y" : b } nell'ordine { "x" : 1, "y" : -1 } tale che (i, j) < (a, b) . Data la specifica di ordinamento, ciò equivale alla condizione i < a o i = a e 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

Infine, nel tuo caso di un indice composto in tre parti

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

il rank funzione sarebbe

> 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 } }
        ]
    })
}