繁体   English   中英

如何对MongoDB中的聚合查询结果分页并得到总文档数(Node.js + Mongoose)?

[英]How to paginate aggregation query results in MongoDB and get a total document count (Node.js + Mongoose)?

我想通过 $limit 和 $skip 对我的查询结果进行分页,并获得通过查询的文档总数。

我现在对结果进行分页是这样的:

  const startIndex = (page - 1) * limit
  const endIndex = page * limit
  const resultObject = {}

  resultObject.totalCount = await model.countDocuments(query).exec()

  if (endIndex < results.totalCount)
    resultObject.next = {page: page + 1, limit}

  if (startIndex > 0)
    results.prev = {page: page - 1, limit}

  resultObject.results = await query.limit(limit).skip(startIndex).exec()

这会产生 2 个问题:

  • 我执行查询两次(你甚至可以在 1 中执行此操作吗?)
  • 出于某种原因,当我的查询是一个聚合时, countDocuments返回 0,即使当我执行query.exec()时我得到正确的结果(> 0)

所以我的问题是如何在获取文档计数的同时对结果进行分页,就像我现在只使用 1 个查询(并使其与聚合查询一起使用)这样我就可以构建我的resultObject

  • “我执行查询两次(你甚至可以在 1 中执行此查询吗?)”不,你不能,实现此目的的唯一方法是获取整个集合,然后在代码中返回所需的文档,这显然是一个非常糟糕的解决方案。

  • 现在这有点棘手,从技术上讲, countDocuments是一个只执行管道的包装器:

该方法用 $sum 表达式包装 $group 聚合阶段以执行计数

意义

db.collection.countDocuments({});

等于:

db.collection.aggregate([
    {
        $group: {
            _id: null,
            count: {$sum: 1}
        }
    }
]);

然而,不同的驱动程序以不同的方式支持此命令,例如nodejs Mongo 驱动程序不允许使用此处指定的某些表达式。 您还使用mongoose ,它可能有其他更改。

如果不查看您的确切查询,就很难说出它失败的原因,但是如果您找不到我推荐的原因,那就是执行包装管道。

我找到了一种方法来获取查询的结果并在同一次“旅行”中对数据库进行计数(仍然是 2 个查询,但在数据库中,因此速度快得多)

关键是使用$facet (mongodb 3.4+):

const pipeline = [
  {YOUR_QUERY},
  {
    $facet: {
      paginatedResults: [{$skip: startIndex}, {$limit: limit}],
      totalCount: [{$count: 'count'}]
    }
  },
  {
    $addFields: {
      total: {
        $ifNull: [{ $arrayElemAt: ['$totalCount.count', 0]}, 0]
      }
    }
  },
  {
    $project: {
      paginatedResults: 1,
      total: 1
    }
  }
]

解释$facet在同一个输入(我们的查询结果)上执行多个管道,我们可以有 1 个管道用于对结果进行分页,1 个用于计算总数。

由于$count返回一个包含count字段的 object,并且 facet 包装在一个数组中,因此$addFields管道将实际count数值提取为total字段。 然后我只使用$project删除不再需要的totalCount ,这就是结果:

  {
     paginatedResults: [RESULTS],
     total: 34
  }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM