You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Mongoose Aggregate方法实现分页及总文档数查询求助

使用Mongoose Aggregate实现分页并获取总文档数

你可以通过$facet聚合阶段在单次查询中同时获取分页数据和总文档数,这比两次查询更高效。以下是正确的实现方式:

完整聚合查询代码

const { skip, searchlimit } = getPagination(params);

const aggregateResult = await TransactionModel.aggregate([
  // 过滤当前用户的交易记录
  { $match: { transactionOwnerId: user?._id } },
  // 使用$facet并行执行两个聚合管道
  {
    $facet: {
      // 处理分页数据(排序、跳过、限制)
      paginatedTransactions: [
        { $sort: { createdAt: -1 } },
        { $skip: skip },
        { $limit: searchlimit }
      ],
      // 统计总文档数
      totalCount: [
        { $count: 'total' }
      ]
    }
  },
  // 将总文档数从数组转为单个数值
  {
    $project: {
      paginatedTransactions: 1,
      total: { $arrayElemAt: ['$totalCount.total', 0] }
    }
  },
  // 处理无文档时的默认值
  {
    $set: {
      total: { $ifNull: ['$total', 0] }
    }
  }
]);

// 提取结果
const { paginatedTransactions, total } = aggregateResult[0];
const transactionsData = paginatedTransactions as transactionAttributes[];
const totalDocumentSize = total;

console.log(transactionsData, totalDocumentSize);

代码解析

  1. $match:先过滤出当前用户的交易记录,和你原有find查询的条件一致。
  2. $facet:允许在一次聚合中同时运行多个独立的管道:
    • paginatedTransactions管道:负责排序、跳过指定数量的文档、限制返回结果数量,实现分页逻辑。
    • totalCount管道:使用$count统计符合条件的总文档数,返回格式为[{ total: 数字 }]。
  3. $project:将总文档数从数组中提取为单个数值,避免后续处理数组的麻烦。
  4. $set:当没有符合条件的文档时,total会被设为0,防止出现undefined。

你之前的聚合查询返回空数组的可能原因

如果你的测试聚合返回空数组,大概率是因为transactionOwnerId的类型不匹配:

  • 若transactionOwnerId在Schema中定义为ObjectId,但你传入的user?._id是字符串,需要先转换为ObjectId:
    const mongoose = require('mongoose');
    // 在$match中使用转换后的ObjectId
    { $match: { transactionOwnerId: mongoose.Types.ObjectId(user._id) } }
    

优势对比

这种方式只需要扫描一次数据库集合,替代了原有两次查询(find+countDocuments)的逻辑,减少了数据库IO操作,性能更优。

内容的提问来源于stack exchange,提问作者valve

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 21:36:01