如何高效查询MongoDB中不含有效content.id的文档?
更优MongoDB多场景查询方案(适配content字段各类无效状态)
需求回顾
需要查询集合中除_id=1(含有效content.id)之外的所有文档,覆盖以下6种无效场景:
content字段不存在content为nullcontent是空对象{}content是空数组[]content存在但不含id字段content存在但content.id为null
原有方案的问题
之前用$or组合两个条件的写法虽然能覆盖场景,但查询性能较差——因为$or在没有针对性索引的情况下容易触发全表扫描,且多条件组合会增加查询引擎的计算开销。
最优查询方案
直接用反向排除逻辑($nor)替代正向匹配,只排除「有有效content.id」的文档,同时排除_id=1的目标文档:
db.collection.find({ "_id": { "$ne": 1 }, "$nor": [ { "content.id": { "$exists": true, "$ne": null } } ] })
方案优势&场景覆盖说明
- 天然覆盖所有需求场景:
$nor会排除所有满足「content.id存在且不为null」的文档,剩下的恰好是你需要的6种无效场景:content不存在/为null:无法解析content.id,自然不满足排除条件content是空对象/无id字段:content.id不存在,不满足排除条件content是空数组:数组无元素,content.id无匹配项,不满足排除条件content.id为null:不满足$ne: null,不被排除
- 性能大幅提升:
给content.id创建单字段索引(db.collection.createIndex({"content.id": 1}))后,查询会直接走索引扫描,比$or方案的效率高很多——因为$nor配合单个索引即可完成过滤,无需多索引合并或全表扫描。 - 适配PHP的空结构转换:
不管PHP将空数组转为对象还是数组,只要content是空结构,就不会存在有效content.id,都会被该查询匹配到。
验证示例
假设集合中有以下测试文档:
[ {"_id":1, "content":{"id":123}}, // 需排除 {"_id":2}, // content不存在,需返回 {"_id":3, "content":null}, // content为null,需返回 {"_id":4, "content":{}}, // 空对象,需返回 {"_id":5, "content":[]}, // 空数组,需返回 {"_id":6, "content":{"name":"test"}}, // 无id字段,需返回 {"_id":7, "content":{"id":null}} // content.id为null,需返回 ]
执行上述查询后,会返回_id=2~7的所有文档,完全符合需求。
内容的提问来源于stack exchange,提问作者Bogdan Dubyk
相关产品推荐
相关产品推荐

