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

时间:2011-06-27 20:22:46

标签: mongodb

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

{
  'blog_id':xxx,
  'timestamp':xxx,
  'title':xxx,
  'content':xxx
}

正如问题所说,有没有办法为每个博客选择最后3个条目?

4 个答案:

答案 0 :(得分:12)

您需要先按blog_idtimestamp字段对集合中的文档进行排序,然后执行一个初始组,该组按降序创建原始文档的数组。之后,您可以使用文档切割数组以返回前3个元素。

在这个例子中可以遵循直觉:

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

答案 1 :(得分:2)

如果你可以忍受两件事,那么在基本的mongo中这样做的唯一方法是:

  • 输入文档中的其他字段,我们称之为“年龄”
  • 新博客条目进行了额外更新

如果是这样,你就是这样做的:

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

    db.entries.update({blog_id:BLOG_ID},{age:{$ inc:1}},false,true)

  2. 查询时,请使用以下查询,该查询将返回每个博客的最新3个条目:

    db.entries.find({age:{$ lte:3},timestamp:{$ gte:STARTOFMONTH,$ lt:ENDOFMONTH}})。sort({blog_id:1,age:1})

  3. 请注意,此解决方案实际上是并发安全的(没有重复年龄的条目)。

答案 2 :(得分:1)

这个答案使用地图减少drcosta从另一个问题做了诀窍

In mongo, how do I use map reduce to get a group by ordered by most recent

mapper = function () {
  emit(this.category, {top:[this.score]});
}

reducer = function (key, values) {
  var scores = [];
  values.forEach(
    function (obj) {
      obj.top.forEach(
        function (score) {
          scores[scores.length] = score;
      });
  });
  scores.sort();
  scores.reverse();
  return {top:scores.slice(0, 3)};
}

function find_top_scores(categories) {
  var query = [];
  db.top_foos.find({_id:{$in:categories}}).forEach(
    function (topscores) {
      query[query.length] = {
        category:topscores._id,
        score:{$in:topscores.value.top}
      };
  });
  return db.foo.find({$or:query});

答案 3 :(得分:0)

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

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