Mongoose统计所有文档tags数组元素频次及总数量(支持百分比计算)
用Mongoose Aggregation统计标签出现次数及百分比
嘿,刚接触Mongoose聚合的话,这个需求其实用Aggregation Pipeline就能完美解决——比map/reduce高效得多,而且是MongoDB官方推荐的统计方式。咱们直接上可运行的方案:
假设你的Mongoose模型是YourModel(比如文章、商品这类带tags字段的模型),以下是完整的聚合代码:
YourModel.aggregate([ // 1. 把每个文档的tags数组拆成单个元素的独立文档 { $unwind: '$tags' }, // 2. 并行执行两个统计任务:标签次数、总标签数量 { $facet: { tagCounts: [ { $group: { _id: '$tags', count: { $sum: 1 } } } ], totalTags: [ { $group: { _id: null, total: { $sum: 1 } } } ] } }, // 3. 提取总标签数量,方便后续计算百分比 { $addFields: { total: { $arrayElemAt: ['$totalTags.total', 0] } } }, // 4. 展开标签统计数组,逐个处理每个标签 { $unwind: '$tagCounts' }, // 5. 整理输出字段,计算百分比(保留2位小数) { $project: { tag: '$tagCounts._id', count: '$tagCounts.count', percentage: { $round: [ { $multiply: [{ $divide: ['$tagCounts.count', '$total'] }, 100] }, 2 ] } } }, // 可选:按出现次数降序排列,方便查看热门标签 { $sort: { count: -1 } } ]) .then(results => { // 把结果转成你想要的 {A:2, B:2,...} 格式(同时保留百分比) const tagStats = results.reduce((acc, item) => { acc[item.tag] = { count: item.count, percentage: `${item.percentage}%` }; return acc; }, {}); const totalTags = results[0]?.total || 0; console.log('标签统计结果:', tagStats); console.log('总标签数量:', totalTags); }) .catch(err => console.error('聚合查询出错:', err));
代码步骤解释:
- $unwind: '$tags':把每个带
tags数组的文档拆分成多条单标签文档,比如tags: ['A','B']会变成两条文档,分别是tags: 'A'和tags: 'B',这是统计数组元素的基础。 - $facet:并行执行两个统计流程,避免多次查询:
tagCounts:按标签分组,统计每个标签的出现次数;totalTags:全局分组(_id: null),统计所有标签的总数量。
- $addFields:从
totalTags数组里提取出总数量值,方便后续计算百分比。 - $project:重新整理输出字段,用
$divide计算占比,$multiply转成百分比,$round保留两位小数。 - 结果转换:用
reduce把聚合返回的数组转成你需要的键值对格式,同时保留百分比信息。
为什么不用Map/Reduce?
Map/Reduce的性能远不如Aggregation Pipeline,而且语法更复杂,MongoDB官方现在也更推荐用聚合框架来做这类统计需求,尤其是数据量较大的时候,聚合的优势会非常明显。
内容的提问来源于stack exchange,提问作者user2001702
相关产品推荐
相关产品推荐

