MongoDB如何基于timeline数组中CREATED状态对象的date字段筛选文档
你完全不需要新增额外字段再筛选,直接使用$elemMatch查询符即可实现高效筛选,这是性能最优的实现方式,还可以直接利用索引加速查询。
1. 普通查询场景(仅筛选符合条件的文档)
直接使用find方法搭配$elemMatch匹配timeline数组中同时满足status=CREATED且date落在指定时间范围的元素即可,示例如下(以筛选2015年6月的数据为例):
db.你的集合名.find({ timeline: { $elemMatch: { status: "CREATED", date: { $gte: ISODate("2015-06-01T00:00:00Z"), $lt: ISODate("2015-07-01T00:00:00Z") } } } })
你可以提前创建复合索引大幅提升查询性能:
db.你的集合名.createIndex({"timeline.status": 1, "timeline.date": 1})
2. 聚合场景(筛选后需要继续做聚合计算)
直接把上述$elemMatch的匹配条件放到聚合管道的第一个$match阶段即可,第一步就过滤掉所有不符合条件的文档,减少后续聚合的计算量,示例如下:
db.你的集合名.aggregate([ // 首阶段筛选,可走索引 { $match: { timeline: { $elemMatch: { status: "CREATED", date: { $gte: ISODate("2015-06-01T00:00:00Z"), $lt: ISODate("2015-07-01T00:00:00Z") } } } } }, // 后续添加你需要的其他聚合操作,比如分组、统计、投影等 { $group: { _id: "$client.id", totalTransAmount: {$sum: "$amount.amount"} } } ])
方案优势
和你原本「先新增字段再筛选」的思路相比,该方案的性能优势非常明显:
- 不需要遍历全量文档做字段计算,首阶段直接过滤无效数据
- 可以利用提前创建的复合索引,数据量越大性能差距越显著
- 语法更简洁,不需要额外的字段处理逻辑
内容的提问来源于stack exchange,提问作者Alex A.
相关产品推荐
相关产品推荐

