Mongoose如何根据嵌套对象的指定键查询匹配的文档
Mongoose根据嵌套对象键查询文档实现方案
场景说明
现有集合存储结构如下,需要查询ACL嵌套对象中包含指定键(示例为123gd)的文档:
[ { "_id": 1, "first_name": "Tom", "email": "tom@example.com", "ACL": { "123gd": { "read": true, "write": false }, "3sg2w": { "read": true, "write": false } } }, { "_id": 2, "first_name": "Tom", "email": "tom@example.com", "ACL": { "546er": { "read": true, "write": false }, "98trw": { "read": true, "write": false } } } ]
预期返回仅包含ACL.123gd键的_id=1的文档。
实现方案
方案1:$exists点路径查询(优先推荐,性能最优)
MongoDB原生支持通过点分隔路径定位嵌套对象的键,配合$exists操作符判断键是否存在即可,写法最简单、查询效率最高:
// 固定键名写法 const docs = await YourModel.find({ "ACL.123gd": { $exists: true } });
如果查询的键是动态传入的变量,用ES6计算属性写法即可:
const targetAclKey = "123gd"; // 动态传入的键名 const docs = await YourModel.find({ [`ACL.${targetAclKey}`]: { $exists: true } });
该写法可以直接命中路径索引,查询速度远高于其他方案,绝大多数场景下用这个就够了。
方案2:$objectToArray聚合转换(适配复杂键匹配场景)
如果需要做更复杂的键逻辑判断(比如键名正则匹配、批量判断键规则),可以用聚合操作符把嵌套对象转为键值对数组后查询:
const docs = await YourModel.find({ $expr: { $in: [ "123gd", { $map: { input: { $objectToArray: "$ACL" }, in: "$$this.k" } } ] } });
实现逻辑:
- 用
$objectToArray把ACL对象转换为[{k: 键名, v: 键对应值}, ...]格式的数组 - 提取数组中所有
k字段(即原对象的所有键),判断目标键是否在列表中
这个方案灵活性更高,但因为需要运行聚合运算,无法命中普通索引,性能比方案1差,仅在有复杂匹配需求时使用。
❌ 注意:不要使用
$where操作符实现该需求,$where会在MongoDB中执行传入的JS代码,性能极差,且存在注入安全风险。
内容的提问来源于stack exchange,提问作者Avinash A
相关产品推荐
相关产品推荐

