【问题标题】:Limiting results in MongoDB but still getting the full count?限制 MongoDB 中的结果但​​仍然获得完整计数?
【发布时间】:2013-02-24 09:41:46
【问题描述】:

为了速度,我想将查询限制为 10 个结果

db.collection.find( ... ).limit(10)

但是,我也想知道总数,所以说“有 124 个,但我只有 10 个”。有没有很好的有效方法来做到这一点?

【问题讨论】:

    标签: mongodb count limit


    【解决方案1】:

    cursor.count() 应默认忽略 cursor.skip()cursor.limit()

    来源:http://docs.mongodb.org/manual/reference/method/cursor.count/#cursor.count

    【讨论】:

      【解决方案2】:

      默认情况下,count() 会忽略 limit() 并计算整个查询中的结果。 因此,例如,当您这样做时,var a = db.collection.find(...).limit(10); 运行 a.count() 将为您提供查询的总数。

      【讨论】:

      • 您好,如何确保在不使用 count() 的情况下应用了限制器?有没有其他办法?
      • 知道如何在 MongoDB nodejs 驱动程序中执行此操作而无需查询两次吗?
      【解决方案3】:

      做count(1)包括limit和skip。

      【讨论】:

      • 从 mongoengine 开始,TypeError: with_limit_and_skip must be True or False,count(True) 将完成这项工作
      • .count(with_limit_and_skip=True) 将更具可读性
      【解决方案4】:

      @johnnycrab 接受的答案是针对 mongo CLI。

      如果您必须在 Node.js 和 Express.js 中编写相同的代码,则必须像这样使用它才能使用“count”函数以及 toArray 的“result”。

      var curFind = db.collection('tasks').find({query});
      

      然后你可以像这样在它之后运行两个函数(一个嵌套在另一个中)

      curFind.count(function (e, count) {
      
      // Use count here
      
          curFind.skip(0).limit(10).toArray(function(err, result) {
      
          // Use result here and count here
      
          });
      
      });
      

      【讨论】:

        【解决方案5】:

        有一个使用push和slice的解决方案:https://stackoverflow.com/a/39784851/4752635

        我喜欢

        1. 首先进行过滤,然后按 ID 分组以获取过滤元素的数量。不要在这里过滤,没有必要。
        2. 过滤、排序和分页的第二个查询。

        推送 $$ROOT 和使用 $slice 的解决方案会遇到 16MB 的文档内存限制,以用于大型集合。此外,对于大型集合,两个查询一起运行似乎比使用 $$ROOT 推送的查询运行得更快。您也可以并行运行它们,因此您只会受到两个查询中较慢的查询(可能是排序的那个)的限制。

        我已经使用 2 个查询和聚合框架解决了这个解决方案(注意 - 我在这个例子中使用了 node.js,但想法是一样的):

        var aggregation = [
          {
            // If you can match fields at the begining, match as many as early as possible.
            $match: {...}
          },
          {
            // Projection.
            $project: {...}
          },
          {
            // Some things you can match only after projection or grouping, so do it now.
            $match: {...}
          }
        ];
        
        
        // Copy filtering elements from the pipeline - this is the same for both counting number of fileter elements and for pagination queries.
        var aggregationPaginated = aggregation.slice(0);
        
        // Count filtered elements.
        aggregation.push(
          {
            $group: {
              _id: null,
              count: { $sum: 1 }
            }
          }
        );
        
        // Sort in pagination query.
        aggregationPaginated.push(
          {
            $sort: sorting
          }
        );
        
        // Paginate.
        aggregationPaginated.push(
          {
            $limit: skip + length
          },
          {
            $skip: skip
          }
        );
        
        // I use mongoose.
        
        // Get total count.
        model.count(function(errCount, totalCount) {
          // Count filtered.
          model.aggregate(aggregation)
          .allowDiskUse(true)
          .exec(
          function(errFind, documents) {
            if (errFind) {
              // Errors.
              res.status(503);
              return res.json({
                'success': false,
                'response': 'err_counting'
              });
            }
            else {
              // Number of filtered elements.
              var numFiltered = documents[0].count;
        
              // Filter, sort and pagiante.
              model.request.aggregate(aggregationPaginated)
              .allowDiskUse(true)
              .exec(
                function(errFindP, documentsP) {
                  if (errFindP) {
                    // Errors.
                    res.status(503);
                    return res.json({
                      'success': false,
                      'response': 'err_pagination'
                    });
                  }
                  else {
                    return res.json({
                      'success': true,
                      'recordsTotal': totalCount,
                      'recordsFiltered': numFiltered,
                      'response': documentsP
                    });
                  }
              });
            }
          });
        });
        

        【讨论】:

        【解决方案6】:

        您可以使用$facet 阶段,该阶段在同一输入文档集的单个阶段内处理多个聚合管道:

        // { item: "a" }
        // { item: "b" }
        // { item: "c" }
        db.collection.aggregate([
          { $facet: {
            limit: [{ $limit: 2 }],
            total: [{ $count: "count" }]
          }},
          { $set: { total: { $first: "$total.count" } } }
        ])
        // { limit: [{ item: "a" }, { item: "b" }], total: 3 }
        

        这样,在同一个查询中,您可以获得一些文档 (limit: [{ $limit: 2 }]) 和文档总数 ({ $count: "count" })。

        最后的$set 阶段是一个可选的清理步骤,只是为了投射$count 阶段的结果,这样"total" : [ { "count" : 3 } ] 就变成了total: 3

        【讨论】:

          猜你喜欢
          • 2011-09-16
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-04-01
          • 1970-01-01
          相关资源
          最近更新 更多