根据排序顺序获取文档在集合中的位置

时间:2014-04-06 19:19:57

标签: javascript mongodb mongoose mapreduce

我是MongoDB(+ Mongoose)的新手。我有一个高分的集合,文档看起来像这样:

{id: 123, user: 'User14', score: 101}
{id: 231, user: 'User10', score: 400}
{id: 412, user: 'User90', score: 244}
{id: 111, user: 'User12', score: 310}
{id: 221, user: 'User88', score: 900}
{id: 521, user: 'User13', score: 103}

+ thousands more...

现在我得到了前五名的球员​​:

highscores
    .find()
    .sort({'score': -1})
    .limit(5)
    .exec(function(err, users) { ...code... });

这很棒,但我还想提出一个问题,例如“{1}}在高分榜上有什么位置?”

这可能以某种方式通过查询实现吗?

2 个答案:

答案 0 :(得分:7)

如果您不必实时获得该位置,Neil Lunn的答案是完美的。但是,如果您的应用始终在此集合中插入数据,则对于新数据,您无法获取该数据。

这是另一种解决方案:

首先,在此集合中的字段分数上添加索引。然后使用查询db.highscores.count({score:{$gt: user's score})。它将计算分数大于目标的文档。这个数字就是展示位置。

答案 1 :(得分:2)

可以使用mapReduce执行此操作,但它确实要求您在已排序的字段上有索引,所以首先,如果您还没有完成:

db.highscores.ensureIndex({ "score": -1 })

然后你可以这样做:

db.highscores.mapReduce(
    function() {
        emit( null, this.user );
    },
    function(key,values) {
        return values.indexOf("User12") + 1;
    },
    {
        "sort": { "score": -1 },
        "out": { "inline": 1 }
    }
)

或者将其与您需要返回的信息区分开来,而不仅仅是"排名"位置。但是,由于这基本上是将所有内容放入已按分数排序的大型数组中,因此对于任何合理大小的数据而言,它可能不是最佳性能。

更好的解决方案是保持单独的排名"集合,您可以使用mapReduce定期更新,即使它没有做任何减少:

db.highscores.mapReduce(
    function() {
        ranking++;
        emit( ranking, this );
    },
    function() {},
    {
        "sort": { "score": -1 },
        "scope": { "ranking": 0 },
        "out": {
            "replace": "rankings"
        }
    }
)

然后,您可以查询此集合以获得结果:

db.rankings.find({ "value.user": "User12 })

所以这将包含排名为"排放"在"排名"的_id字段中集合。