在MongoDB中限制结果但仍然可以获得完整计数?

时间:2013-03-08 18:32:20

标签: mongodb

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

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

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

5 个答案:

答案 0 :(得分:36)

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

答案 1 :(得分:24)

执行count(1)包括限制和跳过。

答案 2 :(得分:5)

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

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

答案 3 :(得分:5)

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

如果你必须在Node.js和Express.js中编写相同的代码,你必须像这样使用它才能使用" count"功能以及toArray"结果"。

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

    });

});

答案 4 :(得分:0)

使用推送和切片有一个解决方案:https://stackoverflow.com/a/39784851/4752635

我优先

  1. 首先进行过滤,然后按ID分组以获取已过滤元素的数量。不要在这里过滤,这是不必要的。
  2. 过滤,排序和分页的第二个查询。
  3. 推送$$ 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
                });
              }
          });
        }
      });
    });