【问题标题】:Mongodb limit array within aggregate query聚合查询中的MongoDB限制数组
【发布时间】:2014-09-07 15:08:06
【问题描述】:

我正在尝试编写一个查询来返回每个类别的前 X 个术语 - 例如前 5 名,前 10 名等。每个术语都有一个相关的类别,并且基于另一个 stackoverflow question 的一些帮助,我设法得到了这个:

db.collection.aggregate([
  { 
    $group : { 
      _id :  { 
        category: "$uri.category",
        term: "$uri.term",
      },
      total: { $sum : 1 } 
    }
  },
  { $sort : { total : -1 } },
  { 
    $group : { 
        _id :  "$_id.category",
        terms: { 
            $push: { 
                term: "$_id.term",
                total: "$total"
            }
        }
     }
  }
]);

上述查询确实有效,并返回如下所示的数据:

[
 { category: "movies", 
   terms: [ { term: "movie 1", total: 5000 }, { term: "movie 2", total: 200 } ... ]
 },
 { category: "sports", 
   terms: [ { term: "football 1", total: 4000 }, { term: "tennis 2", total: 250 } ... ]
 },
]

但是,我试图将术语数组限制为固定数字,即 5 或 10 - 这将对应于每个类别的 X 搜索次数。我一直在尝试各种选项,例如在$push 中添加$slice 以减少术语数组,但没有成功。

这可以使用聚合框架来实现吗,还是我应该看看另一种方法?

【问题讨论】:

    标签: mongodb mongodb-query aggregation-framework


    【解决方案1】:

    从 MongoDb 版本 3.1.6 开始,您现在可以在 $project 阶段进行切片:

    {
        $project: {
            terms: {
                $slice: ["$terms", 0, 10]
            }
        }
    }
    

    如果您想将 $pushed 的项目数限制为 10。

    问题来了: https://jira.mongodb.org/browse/SERVER-6074

    【讨论】:

      【解决方案2】:

      似乎从 Mongodb 2.6 开始,不支持使用 $slice$push.aggregate() 函数/命令来限制数组大小的能力。 这是 MongoDb 问题跟踪器上的 feature request

      我要做的是将聚合结果输出到集合中。然后更新集合。

      示例:

      设置:

      use test;
      var rInt = function(x) {
          return 1 + ~~(Math.random() * x);
      };
      var rObj = function() {
          return {
              "timestamp": new Date(),
              "category": "movies" + rInt(5),
              "term": "my movie" + rInt(20)
          }
      };
      for (var i = 0, l = 100; i < l; i++) {
          db.al.insert(rObj());
      }
      

      聚合查询

      db.al_out.drop();
      
      db.al.aggregate([
        { 
          $group : { 
            _id :  { 
              category: "$category",
              term: "$term",
            },
            total: { $sum : 1 } 
          }
        },
        { $sort : { total : -1 } },
        { 
          $group : { 
              _id :  "$_id.category",
              terms: { 
                  $push: { 
                      term: "$_id.term",
                      total: "$total"
                  }
              }
           }
        }
        ,{ $out : "al_out" }  // output the documents to `db.al_out`
      ]);
      
      // limit the size of terms to 3 elements.
      db.al_out.update( {}, {
        $push : {
          terms : { 
            $each : [],
            $slice : 3 
          }
        }
      }, {
        multi:true
      });
      

      结果:

      db.al_out.find();
      
      { "_id" : "movies1", "terms" : [ { "term" : "my movie7", "total" : 3 }, { "term" : "my movie6", "total" : 3 }, { "term" : "my movie17", "total" : 2 } ] }
      { "_id" : "movies2", "terms" : [ { "term" : "my movie3", "total" : 4 }, { "term" : "my movie11", "total" : 2 }, { "term" : "my movie2", "total" : 2 } ] }
      { "_id" : "movies4", "terms" : [ { "term" : "my movie9", "total" : 3 }, { "term" : "my movie1", "total" : 3 }, { "term" : "my movie7", "total" : 2 } ] }
      { "_id" : "movies3", "terms" : [ { "term" : "my movie19", "total" : 5 }, { "term" : "my movie8", "total" : 4 }, { "term" : "my movie14", "total" : 4 } ] }
      { "_id" : "movies5", "terms" : [ { "term" : "my movie7", "total" : 6 }, { "term" : "my movie17", "total" : 4 }, { "term" : "my movie3", "total" : 2 } ] }
      

      【讨论】:

      • 不需要保存额外的集合,您可以使用下一个答案中描述的 Craig 的项目和切片。
      【解决方案3】:

      我会在 $sort 之后和 $group 之前添加一个 $limit 阶段:

      { $limit : 5 },
      

      这应该将随后被推入数组的文档数限制为 5。这也将用于限制排序中内存中维护的文档总数,这应该会提高整体性能:

      当 $sort 紧接在管道中的 $limit 之前时,$sort 操作仅在进行时保持前 n 个结果,其中 n 是指定的限制,MongoDB只需要存储n个项目 记忆。

      http://docs.mongodb.org/manual/reference/operator/aggregation/limit/

      【讨论】:

      • 虽然您是正确的,{ $limit : 5 } 确实将结果限制为 5,但我正在考虑获得每个类别的前 5 名,因此无法解决问题,因为它限制了所有类别。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-11-08
      • 1970-01-01
      • 2020-07-27
      • 1970-01-01
      • 1970-01-01
      • 2014-08-19
      相关资源
      最近更新 更多