MongoDB聚合管道中统计总文档数与匹配文档数的实现问题
MongoDB聚合管道中统计总文档数与匹配文档数的实现问题
嘿,我看了你的聚合管道代码,你已经搞定了总文档数totalCount的统计,现在想让filterCount准确统计出经过$match过滤后的文档数量对吧?
先说说你当前写法的小问题:你把filterCount放在了data管道的$group里,虽然能得到数量,但这样会把所有匹配到的文档都塞到data数组里,而且后续的分页($skip和$limit)是在$group之前执行的,这就导致你的filterCount统计的是分页后的文档数量,而不是所有匹配$match条件的总数量,这肯定不是你想要的结果对吧?
那怎么调整呢?其实我们可以利用$facet的特性,在同一个管道里拆分出三个分支:一个专门统计总文档数,一个专门统计过滤后的总数量,再加上分页后的结果数据,这样三个部分都能准确拿到。
给你调整后的代码:
const doc = await Model.aggregate([ { $facet: { metadata: [{ $count: 'totalCount' }], filterMetadata: [ { $match: { 'sysData.status': 'pending' } }, { $count: 'filterCount' } ], data: [ { $match: { 'sysData.status': 'pending' } }, { $sort: parseSort(req.query.sort) }, { $project: parseFields(req.query.fields) }, { $skip: (parsePage(req.query.page) - 1) * parseLimit(req.query.limit) }, { $limit: parseLimit(req.query.limit) } ] } }, // 最后把结果整理得更简洁 { $project: { totalCount: { $arrayElemAt: ['$metadata.totalCount', 0] }, filterCount: { $arrayElemAt: ['$filterMetadata.filterCount', 0] }, data: 1 } } ]);
解释一下这个写法:
metadata分支保留原来的逻辑,统计整个集合的总文档数。- 新增
filterMetadata分支,先执行和data分支一样的$match条件,再用$count直接得到所有匹配文档的总数,这就是你要的filterCount。 data分支保留原来的过滤、排序、投影、分页逻辑,直接返回分页后的文档列表,不用再用$group打包数据,拿到的data就是直接的文档数组,用起来更顺手。- 最后的
$project阶段,把metadata和filterMetadata里的数组值提取出来(因为$count返回的是单元素数组),让最终结果结构更清晰。
如果你的dataPipeline是封装好的管道逻辑,还可以把重复的$match部分抽出来复用,避免代码冗余:
const matchStage = { $match: { 'sysData.status': 'pending' } }; const dataPipeline = [ matchStage, { $sort: parseSort(req.query.sort) }, { $project: parseFields(req.query.fields) }, { $skip: (parsePage(req.query.page) - 1) * parseLimit(req.query.limit) }, { $limit: parseLimit(req.query.limit) } ]; const doc = await Model.aggregate([ { $facet: { metadata: [{ $count: 'totalCount' }], filterMetadata: [matchStage, { $count: 'filterCount' }], data: dataPipeline } }, { $project: { totalCount: { $arrayElemAt: ['$metadata.totalCount', 0] }, filterCount: { $ifNull: [{ $arrayElemAt: ['$filterMetadata.filterCount', 0] }, 0] }, data: 1 } } ]);
这里还加了$ifNull处理,要是没有匹配到文档,filterCount会显示0而不是null,更符合统计逻辑。
备注:内容来源于stack exchange,提问作者Gerlan Verlouw
相关产品推荐
相关产品推荐

