我是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}}在高分榜上有什么位置?”
这可能以某种方式通过查询实现吗?
答案 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
字段中集合。