43

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

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

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

4

6 回答 6

46

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

于 2013-03-08T18:55:53.797 回答
28

做count(1)包括limit和skip。

于 2014-11-07T17:27:07.277 回答
7

@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

    });

});
于 2016-09-04T21:06:12.833 回答
5

cursor.count()应该忽略cursor.skip()并且cursor.limit()默认情况下。

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

于 2013-03-08T18:54:46.383 回答
0

您可以使用$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.

于 2021-12-03T22:03:11.010 回答
-1

有一个使用推送和切片的解决方案: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
            });
          }
      });
    }
  });
});
于 2017-02-09T17:46:12.820 回答