MongoDB
 sql >> Datenbank >  >> NoSQL >> MongoDB

So erhalten Sie eine Artikelrangfolge in einer Liste, die nach mehreren Feldern in Mongoose sortiert ist

Zählen Sie die Anzahl der Benutzer, die in Ihrer Sortierreihenfolge vor diesem Benutzer stehen. Ich beginne mit dem Fall einer einfachen (nicht zusammengesetzten Sortierung), da die Abfrage im zusammengesetzten Fall komplizierter ist, obwohl die Idee genau dieselbe ist.

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

Für diese Reihenfolge ist das Ranking eines Dokuments { "x" : i } ist die Anzahl der Dokumente { "x" : j } mit 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

Der Rang basiert auf 0. Ähnlich, wenn Sie den Rang für das Dokument { "x" : i } berechnen möchten in der Sortierung { "x" : 1 } , würden Sie die Anzahl der Dokumente { "x" : j } zählen mit i > j .

Für eine zusammengesetzte Sortierung funktioniert das gleiche Verfahren, aber es ist schwieriger zu implementieren, da die Reihenfolge in einem zusammengesetzten Index lexikographisch ist, d. h. für die Sortierung { "a" : 1, "b" : 1} , (a, b) < (c, d) wenn a < c oder a = c und b < d , also brauchen wir eine kompliziertere Abfrage, um diese Bedingung auszudrücken. Hier ist ein Beispiel für einen zusammengesetzten Index:

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

So finden Sie den Rang für das Dokument { "x" : i, "y" : j } , müssen Sie die Anzahl der Dokumente ermitteln { "x" : a, "y" : b } in der Reihenfolge { "x" : 1, "y" : -1 } so dass (i, j) < (a, b) . Aufgrund der Sortierangabe entspricht dies der Bedingung i < a oder i = a und 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

Schließlich in Ihrem Fall eines dreiteiligen zusammengesetzten Index

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

der rank Funktion wäre

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