Mongodb 通过mongo和meteor获得某个特定值的前50项记录

Mongodb 通过mongo和meteor获得某个特定值的前50项记录,mongodb,meteor,mongodb-query,Mongodb,Meteor,Mongodb Query,在我的meteor项目中,我有一个排行榜,它在图表上显示了各个级别的玩家,分布在游戏的各个级别。为了简单起见,假设有1-100级。目前,为了避免meteor过载,我只是告诉服务器给我发送每一条超过两周的记录,但这还不足以获得准确的排行榜 我想做的是显示50条记录,代表每个级别。因此,如果级别1有100条记录,级别2有85条记录,级别3有65条记录,级别4有45条记录,我想显示每个级别最近的50条记录,这样我就可以分别拥有[50,50,50,45]条记录 数据如下所示: { snapsho

在我的meteor项目中,我有一个排行榜,它在图表上显示了各个级别的玩家,分布在游戏的各个级别。为了简单起见,假设有1-100级。目前,为了避免meteor过载,我只是告诉服务器给我发送每一条超过两周的记录,但这还不足以获得准确的排行榜

我想做的是显示50条记录,代表每个级别。因此,如果级别1有100条记录,级别2有85条记录,级别3有65条记录,级别4有45条记录,我想显示每个级别最近的50条记录,这样我就可以分别拥有[50,50,50,45]条记录

数据如下所示:

{
    snapshotDate: new Date(),
    level: 1,
    hp: 5000,
    str: 100
}
{
 level:1,
 records:[{snapshotDate:2,hp:5000,str:100},
          {snapshotDate:1,hp:5001,str:101}]
}

我认为这需要一些mongodb聚合,但我不太明白如何在一个查询中实现这一点。不过,分两次完成这项工作很简单——选择所有记录,按级别分组,按日期对每个级别进行排序,然后从每个级别中提取最后50条记录。然而,如果可以的话,我更愿意一次手术。目前是否可以这样做?

目前无法在聚合管道中获取组的顶部记录。有一个与此相关的未解决票证:

有两种解决方案:

  • 保持文档结构不变并聚合,但是, 抓取
    n
    顶部记录,并在客户端切掉每组的剩余记录
代码:

请记住,这将加载每个
级别的所有文档,并删除客户端中不需要的记录

  • 改变文档结构以实现真正需要的内容。如果 您只需要始终保存最上面的
    n
    记录,并始终将它们排序 在根文档中排序。这是通过使用
您的文档如下所示:

{
    snapshotDate: new Date(),
    level: 1,
    hp: 5000,
    str: 100
}
{
 level:1,
 records:[{snapshotDate:2,hp:5000,str:100},
          {snapshotDate:1,hp:5001,str:101}]
}
其中,
记录
是一个大小为
n
的封顶数组,并且子文档总是按照其
快照日期的降序排序

为了使
记录
数组以这种方式工作,我们总是在需要为任何
级别
向其插入文档时执行更新操作

db.collection.update({"level":1},
            {$push:{
                    recs:{
                          $each:[{snapshotDate:1,hp:5000,str:100},
                                 {snapshotDate:2,hp:5001,str:101}],
                          $sort:{"snapshotDate":-1},
                          $slice:50 //Always trim the array size to 50.
                         }
            }},{upsert:true})
这样做的目的是始终将
记录
数组的大小保持在
50
,并且每当在
级别插入新的子文档时总是对记录进行排序

db.collection.update({"level":1},
            {$push:{
                    recs:{
                          $each:[{snapshotDate:1,hp:5000,str:100},
                                 {snapshotDate:2,hp:5001,str:101}],
                          $sort:{"snapshotDate":-1},
                          $slice:50 //Always trim the array size to 50.
                         }
            }},{upsert:true})

一个简单的查找,
db.collection.find({“level”:{$in:[1,2,…]}}}
,将按顺序为您提供前50条记录,对于每个选定的
级别

,请在集合中发布一个示例文档好吗?当文档结构被清晰地描述时,提供解决方案就变得容易多了。@BatScream我在question.Collection.find({level:1},{limit:50})中添加了文档的一个小版本@Sindis我想找到每个级别的最新50条记录,而不仅仅是一个级别,也不仅仅是50条任意记录。你必须在每个级别上循环它(使用if子句检查是否有记录),并根据你的喜好限制它(限制记录,如果你有45条,它将打印45条,而不是50条)。这是一个有趣的解决方案。从本质上说,我将对输入的数据进行“预排序”(即,“在x级插入此记录,然后根据需要进行排序/切片”)?如果我已经有了一堆记录(分布在100个关卡上的约20k条记录),有没有简单的方法把它们拉进来?另外,如果这不是非常紧急,我可以等到
$slice
的问题得到解决吗?如果你不介意的话,那样的话会是什么样子?是的。你说得对。更新运算符:,是在2.4中为此目的引入的。如果已经有很多记录,可以使用map reduce将它们迁移到新的文档结构中。这将是简单而直接的,但是您需要对现有的应用程序代码进行大量更改,重构查询。话虽如此,如果您刚刚开始编写应用程序代码,您可以采用这种方法。JIRA ticked现在已经开放了大约两年半。我怀疑它是否会很快被修复。如果您选择保持当前文档结构,则需要在客户端执行切片,或者为每个级别启动多个查询,请记住-您肯定必须为每个级别启动至少一个查询。这让事情变得更糟。当然,考虑到日期,这是意料之中的——我最初没有注意到问题的发布日期。嗯,我还有一段时间等待,然后我将需要继续为这个排行榜擦除我的游戏数据,所以我会在那个时候重新评估。现在,我会接受这个答案,因为它是经过深思熟虑的,而且是正确的,尽管需要对结构进行更改。谢谢。非常欢迎您,如果发现其他方法,请更新。
db.collection.update({"level":1},
            {$push:{
                    recs:{
                          $each:[{snapshotDate:1,hp:5000,str:100},
                                 {snapshotDate:2,hp:5001,str:101}],
                          $sort:{"snapshotDate":-1},
                          $slice:50 //Always trim the array size to 50.
                         }
            }},{upsert:true})