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);
代码解析
- $match:先过滤出当前用户的交易记录,和你原有
find查询的条件一致。 - $facet:允许在一次聚合中同时运行多个独立的管道:
paginatedTransactions管道:负责排序、跳过指定数量的文档、限制返回结果数量,实现分页逻辑。totalCount管道:使用$count统计符合条件的总文档数,返回格式为[{ total: 数字 }]。
- $project:将总文档数从数组中提取为单个数值,避免后续处理数组的麻烦。
- $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
相关产品推荐
相关产品推荐

