2012-11-23 82 views
24

假设我有一个名为“上岗”集合(它实际上是一个更复杂的集合,职位过于简单)结构如下:

> db.posts.find() 

{ "id" : ObjectId("50ad8d451d41c8fc58000003"), "title" : "Lorem ipsum", "author" : 
"John Doe", "content" : "This is the content", "tags" : [ "SOME", "RANDOM", "TAGS" ] } 

我希望这个集合要跨越数十万甚至数百万个,我需要通过标记查询帖子并按标记对结果进行分组并显示分页结果。这就是聚合框架进来我打算使用的骨料()方法来查询集合:

db.posts.aggregate(
    { "unwind" : "$tags" }, 
    { "group" : { 
     _id: { tag: "$tags" }, 
     count: { $sum: 1 } 
    } } 
); 

美中不足的是,创建分页程序,我需要知道输出数组的长度。我知道要做到这一点,你可以这样做:

db.posts.aggregate(
    { "unwind" : "$tags" }, 
    { "group" : { 
     _id: { tag: "$tags" }, 
     count: { $sum: 1 } 
    } } 
    { "group" : { 
     _id: null, 
     total: { $sum: 1 } 
    } } 
); 

但是,这将丢弃前一个管道(第一组)的输出。有没有办法将两种操作合并在一起,同时保留每个管道的输出?我知道整个聚合操作的输出可以用某种语言转换为数组,并且可以计算内容,但是流水线输出可能会超过16Mb的限制。另外,为了获得计数而执行相同的查询看起来很浪费。

那么获得文件结果是否可以同时计数呢?任何帮助表示赞赏。

+2

你真的需要一个完全准确的总数,或将逼近呢?然后再次,它看起来像你正在计算所有帖子,所以这不仅仅是一个你可以做的count()操作吗? – cirrus

+0

我实际上是在对一组帖子进行计数,所以count()不会。 – MervS

+0

完美的解决方案,以获得总数,同时保留聚合管道结果 http://stackoverflow.com/a/39784851/3666966 –

回答

30
  1. 使用$project保存tagcounttmp
  2. 使用$pushaddToSettmp存储到您的data列表中。

代码:

db.test.aggregate(
    {$unwind: '$tags'}, 
    {$group:{_id: '$tags', count:{$sum:1}}}, 
    {$project:{tmp:{tag:'$_id', count:'$count'}}}, 
    {$group:{_id:null, total:{$sum:1}, data:{$addToSet:'$tmp'}}} 
) 

输出:

{ 
    "result" : [ 
      { 
        "_id" : null, 
        "total" : 5, 
        "data" : [ 
          { 
            "tag" : "SOME", 
            "count" : 1 
          }, 
          { 
            "tag" : "RANDOM", 
            "count" : 2 
          }, 
          { 
            "tag" : "TAGS1", 
            "count" : 1 
          }, 
          { 
            "tag" : "TAGS", 
            "count" : 1 
          }, 
          { 
            "tag" : "SOME1", 
            "count" : 1 
          } 
         ] 
       } 
     ], 
     "ok" : 1 
} 
+0

我不知道你可以在'$ project'管道的新字段中包含多个字段。这正是我需要的。谢谢。 – MervS

+1

是否可以$ sort,$ skip或$限制使用此方法的数据?您不能在$ project之前限制数据,并且在没有丢失“总数”的情况下我没有办法做到这一点。另外,{$ sort:{'data.count':1}}似乎不像通常在非聚合查询中那样工作。 –

3

我不知道你需要的聚合框架此以外计算的所有变量如:

db.posts.aggregate(
    { "unwind" : "$tags" }, 
    { "group" : { 
     _id: { tag: "$tags" }, 
     count: { $sum: 1 } 
    } } 
); 

对于每个标签,你可以只使用正常的查询语法通过分页 - 像这样:

db.posts.find({tags: "RANDOM"}).skip(10).limit(10) 
+0

这将工作,如果我正在搜索标签“随机”的所有职位,但我实际上是分组职位通过他们的标签和由此产生的组是什么是需要分页。 – MervS

+0

啊,我不确定! – Ross