如何基于MongoDB唯一字段实现分页并获取唯一记录总数?
解决方案
1. 修复唯一记录总数统计的问题
你之前的await Token.find().distinct('token_id').countDocuments().exec()写法错误,因为distinct()返回的是包含唯一值的数组Promise,并非Mongoose的Query对象,无法链式调用countDocuments()。要高效统计唯一token_id的数量,直接用聚合的$group+$count即可,无需拉取全量数据:
const getUniqueTokenCount = async () => { const result = await Token.aggregate([ { $group: { _id: '$token_id' } }, { $count: 'total' } ]).exec(); return result.length > 0 ? result[0].total : 0; };
2. 结合分页与总数的高效聚合方案
如果想通过一次数据库请求同时拿到分页数据和唯一总数,可使用$facet聚合阶段,它能在一个聚合管道中并行执行多个子管道,分别返回不同结果:
const getUniqueTokensWithPagination = async (offset = 0, limit = 100) => { const [result] = await Token.aggregate([ // 按token_id分组,保留每组第一条文档实现去重 { $group: { _id: '$token_id', doc: { $first: '$$ROOT' } } }, // 并行处理总数统计和分页逻辑 { $facet: { totalCount: [{ $count: 'value' }], paginatedData: [ { $skip: offset }, { $limit: limit }, { $replaceRoot: { newRoot: '$doc' } } ] } } ]).exec(); return { total: result.totalCount.length > 0 ? result.totalCount[0].value : 0, data: result.paginatedData }; };
代码说明
$group阶段:按token_id分组,用$first保留每组的第一条文档,完成去重操作。$facet阶段:totalCount子管道:对分组后的结果计数,得到唯一记录的总数。paginatedData子管道:先执行$skip和$limit完成分页,再用$replaceRoot将分组后保留的文档恢复为原结构。
- 该方案仅需一次数据库请求,全程在MongoDB端处理数据,不会将全量数据加载到Node应用内存中。
替代方案:分开查询总数与分页数据
若不想使用$facet,也可分开调用两个聚合方法(会多一次数据库请求):
// 获取唯一记录总数 const total = await getUniqueTokenCount(); // 获取分页去重数据 const data = await Token.aggregate([ { $group: { _id: '$token_id', doc: { $first: '$$ROOT' } } }, { $replaceRoot: { newRoot: '$doc' } }, { $skip: offset }, { $limit: limit } ]).exec(); return { total, data };
内容的提问来源于stack exchange,提问作者Rafee
相关产品推荐
相关产品推荐

