Mongodb:从每个组中选择前N行

Mongodb:从每个组中选择前N行,mongodb,Mongodb,我使用mongodb作为我的博客平台,用户可以在这里创建自己的博客。来自所有博客的所有条目都在条目集合中。条目的文档如下所示: { 'blog_id':xxx, 'timestamp':xxx, 'title':xxx, 'content':xxx } 正如问题所说,是否有任何方法可以为每个博客选择(比如)最后3个条目?可以使用组(聚合),但这将创建一个完整的表扫描 你真的需要3篇吗?或者你能设定一个限制吗…例如:上周/月最多3篇帖子?如果你能接受两件事,那么在基本mongo中

我使用mongodb作为我的博客平台,用户可以在这里创建自己的博客。来自所有博客的所有条目都在条目集合中。条目的文档如下所示:

{
  'blog_id':xxx,
  'timestamp':xxx,
  'title':xxx,
  'content':xxx
}
正如问题所说,是否有任何方法可以为每个博客选择(比如)最后3个条目?

可以使用组(聚合),但这将创建一个完整的表扫描


你真的需要3篇吗?或者你能设定一个限制吗…例如:上周/月最多3篇帖子?

如果你能接受两件事,那么在基本mongo中实现这一点的唯一方法是:

  • 您的输入文档中还有一个字段,我们称之为“年龄”
  • 一个新的博客条目进行了额外的更新
如果是这样的话,以下是您的做法:

  • 创建新的介绍后,执行正常的插入,然后执行此更新以增加所有帖子(包括您刚才为此博客插入的帖子)的年龄:

    update({blog\u id:blog\u id},{age:{$inc:1}},false,true)

  • 查询时,使用以下查询将返回每个博客最近的3个条目:

    查找({age:{$lte:3},时间戳:{$gte:STARTOFMONTH,$lt:ENDOFMONTH})。排序({blog_id:1,age:1})


  • 请注意,此解决方案实际上是并发安全的(没有重复期限的条目)

    这个答案使用了另一个问题的drcosta的map reduce


    您需要首先按照
    blog\u id
    timestamp
    字段对集合中的文档进行排序,然后进行初始分组,按降序创建原始文档的数组。之后,可以使用文档对数组进行切片,以返回前3个元素

    在本例中,可以遵循直觉:

    db.entries.aggregate([
        { '$sort': { 'blog_id': 1, 'timestamp': -1 } }, 
        {       
            '$group': {
                '_id': '$blog_id',
                'docs': { '$push': '$$ROOT' },
            }
        },
        {
            '$project': {
                'top_three': { 
                    '$slice': ['$docs', 3]
                }
            }
        }
    ])
    

    理想情况下,我只想选择3篇,但如果我除了数据非规范化之外找不到解决方案,上个月最多3篇文章就足够了。你能给我举个例子说明如何做到这一点吗?从我读过的所有mongodb的map reduce教程中,它们只显示了如何计算统计数据(聚合)…明白你的想法了。我没想到会有这样的事。创建新帖子时进行额外更新不会有问题。但是,当用户删除一篇文章时,我们必须更新所有其他文章的“年龄”字段。只有当被删除的帖子有“年龄”时,更新才能被限制。是的,你不应该将更新限制在年龄<3岁,因为你最终会有重复的年龄。就地更新速度非常快,所以应该不会有问题。删除意味着删除条目并将年龄减少1,其中年龄>已删除\ u post.age。祝你好运,这绝对有道理。谢谢你的建议!它适用于少量记录和罕见的更新,但当我需要从两个用户之间的每次对话中获取最后一条消息时,当我每分钟有数千条消息和许多新消息时,将它与消息传递系统一起使用是否有效?我认为每次更新数千条信息的“年龄”是无效的。您能为这种情况提供一些建议吗?@oyatek有点取决于您的确切用例和读/写比率。如果你打开一个关于你的具体问题的问题,我会看一看。自从聚合变得可用以来,现在这是更好的答案。如果每个组都有数千个文档,我想组阶段会将它们全部保存在
    文档
    数组中,而我们只需要最后3个,而不必保留任何其他内容。您知道Mongo4.2中是否有更有效的方法(在
    文档中最多保存3个文档
    )吗?(我想在4.4中可以使用自定义累加器函数。)
    db.entries.aggregate([
        { '$sort': { 'blog_id': 1, 'timestamp': -1 } }, 
        {       
            '$group': {
                '_id': '$blog_id',
                'docs': { '$push': '$$ROOT' },
            }
        },
        {
            '$project': {
                'top_three': { 
                    '$slice': ['$docs', 3]
                }
            }
        }
    ])