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