MongoDB(mongoose/node)无需countDocuments、distinct统计唯一值数量
MongoDB 去重字段计数高效实现方案
1. 优先添加覆盖索引
你的聚合性能瓶颈90%以上来自没有匹配的索引,直接添加以下复合索引即可实现索引覆盖扫描,不需要回表查询原始文档,百万级数据下性能可提升5~10倍:
// mongoose 侧创建索引代码 YourModelSchema.index({ isSent: 1, documentStatus: 1, documentId: 1 });
如果其他计数规则用到其他过滤字段,可以把对应字段也加入索引,保证所有聚合的$match和$group用到的字段都在索引中即可。
2. 单聚合管道批量计算所有计数器
不要分开跑7~8次聚合请求,使用$facet阶段在单次聚合请求中完成所有计数统计,大幅减少数据库交互开销和重复数据扫描成本:
const stats = await YourModel.aggregate([ // 第一步先过滤出所有计数规则覆盖的所有文档,缩小后续处理范围 { $match: { $or: [ { isSent: true, documentStatus: 'Sent' }, { isRead: true, documentStatus: 'Read' }, // 其他计数规则的过滤条件统一放这里 ] } }, // 多分支并行计算不同计数 { $facet: { sentDocumentCount: [ { $match: { isSent: true, documentStatus: 'Sent' } }, { $group: { _id: '$documentId' } }, { $count: 'count' } ], readDocumentCount: [ { $match: { isRead: true, documentStatus: 'Read' } }, { $group: { _id: '$documentId' } }, { $count: 'count' } ] // 剩余其他计数规则按上面格式添加即可 } } ]); // 取值方式 const sentCount = stats[0].sentDocumentCount[0]?.count || 0;
3. 可选:低实时性场景加预缓存
如果计数统计对实时性要求不高(允许1~5分钟延迟),可以加定时任务定期跑聚合,把结果存在Redis或者专门的统计集合中,业务侧直接读缓存结果,响应速度可以到毫秒级。
内容的提问来源于stack exchange,提问作者AxelBlaze
相关产品推荐
相关产品推荐

