Mongoose使用includes查询ObjectId数组元素返回false问题排查
问题原因
Array.includes() 底层使用严格相等逻辑(和===判断规则一致)做匹配,返回false的核心原因有两个:
- Mongoose查询返回的文档中,
friends字段里存储的是Mongoose封装的ObjectId类型实例,属于引用类型值。哪怕两个ObjectId实例对应的ID字符串完全相同,只要是两个独立创建的实例,严格相等判断就会返回false。 - 字符串类型的ID和
ObjectId实例类型不同,严格相等判断自然无法匹配。
解决方案
根据使用场景可以选以下任意一种方案:
方案1:统一转字符串比较(最简单)
把所有待匹配的ID和查询目标都转为字符串类型,再做includes判断,值相等就可以匹配成功:
const mongoose = require("mongoose"); const ObjectId = mongoose.Types.ObjectId; const testIncludes = async () => { let neighbors = await Neighbor.find(); let friends_ids = []; neighbors.forEach((neighbor) => { // 把每个ObjectId转成字符串再存入数组 const friendStrIds = neighbor.friends.map(id => id.toString()); friends_ids.push(...friendStrIds); }); const element_to_search = "60dcbb29118ea36a4f3ce229"; // 字符串值相等即可匹配 let is_element_found = friends_ids.includes(element_to_search); console.log(is_element_found); }; testIncludes();
方案2:使用ObjectId自带的equals方法判断
ObjectId实例自带equals()方法,专门用于判断两个ObjectId是否代表同一个ID值,配合Array.some()遍历判断即可:
const mongoose = require("mongoose"); const ObjectId = mongoose.Types.ObjectId; const testIncludes = async () => { let neighbors = await Neighbor.find(); let friends_ids = []; neighbors.forEach((neighbor) => { friends_ids.push(...neighbor.friends); }); const element_to_search = ObjectId("60dcbb29118ea36a4f3ce229"); // 调用equals方法做值比较,避开引用类型严格相等的问题 let is_element_found = friends_ids.some(id => id.equals(element_to_search)); console.log(is_element_found); }; testIncludes();
方案3:直接在数据库层做判断(性能最优,推荐)
不需要把所有neighbor文档全量查到内存里拼接数组,直接用MongoDB的数组查询语法,在数据库层面判断是否存在包含目标好友ID的邻居文档,数据量大的时候性能远高于内存判断:
const mongoose = require("mongoose"); const ObjectId = mongoose.Types.ObjectId; const testExists = async () => { const targetId = ObjectId("60dcbb29118ea36a4f3ce229"); // 查询任意一个friends数组包含targetId的邻居文档 const matchedNeighbor = await Neighbor.findOne({ friends: targetId }); const is_element_found = !!matchedNeighbor; console.log(is_element_found); }; testExists();
注意:原代码中使用
map方法做数组遍历拼接但没有利用map的返回值,属于不规范写法,遍历做副作用操作建议用forEach替代。
内容的提问来源于stack exchange,提问作者AG_HIHI
相关产品推荐
相关产品推荐

