为何Array.some()在Mongoose用户请求检查中始终返回false?
问题还原
我当初踩过一模一样的坑!你用Express写路由时,明明userID和request.user的ID值看起来完全一致,但listing.requests.some()就是顽固返回false——哪怕在MDN控制台用类似字符串测试能正常返回true,换成Mongoose里的ObjectId就失效,甚至写死字符串ID也没用,这全是因为Mongoose的ObjectId是对象类型,不是普通字符串!
根因分析
你的Mongoose Schema里定义requests.user为ObjectId类型,它本质是一个ObjectId实例对象。而你用来对比的userID可能是字符串,或者是另一个独立的ObjectId实例。JavaScript里用===直接比较时,检查的是两个值的引用是否相同,不是实际ID值是否一致。哪怕两个ObjectId的字符串表示完全一样,只要是不同实例,===就会返回false,自然导致some()找不到匹配项。
而你在MDN控制台测试时用的是普通字符串或同一个对象,自然能正常匹配,这就是为啥本地测试没问题,到Mongoose里就出状况。
解决方案
有两种简单可靠的解决方式:
方案1:转字符串后对比
直接调用ObjectId的toString()方法,把两边都转为字符串再做值比较:
const hasRequested = listing.requests.some(req => req.user.toString() === userID.toString());
不管userID是字符串还是ObjectId实例,转成字符串后就能用值相等来判断了。
方案2:用ObjectId自带的equals()方法
Mongoose的ObjectId实例自带equals()方法,专门用来对比ID值是否一致,自动处理字符串和ObjectId实例的兼容:
const hasRequested = listing.requests.some(req => req.user.equals(userID));
这个方法比手动转字符串更优雅,也是Mongoose官方推荐的ID对比方式。
小提醒
以后碰到Mongoose里的ID对比,别直接用===,优先用equals()或者转字符串的方式,能避开很多这种“看起来一样但不相等”的隐形坑。
内容的提问来源于stack exchange,提问作者Zitrooone

