如何在JS中检测用户是否已存在于Game的players_list中
嘿,我来帮你搞定这个判断失效的问题!
为什么你的判断会失效?
你现在用e._id === req.user._id来做比较,但这里有个关键细节:Mongoose中的_id是ObjectId类型的对象,不是普通字符串。哪怕两个ObjectId的字符串值完全一样,它们也是不同的对象实例,用===比较的是对象的引用地址,而不是实际的ID值——所以哪怕用户确实在players_list里,这个判断也会返回false,导致逻辑失效。
从你给出的Game实例和User实例来看,players_list里的用户_id和目标用户的_id字符串值是匹配的,但因为是ObjectId对象,直接用===就会出错。
正确的检测方法
这里有几种靠谱的解决方式,按推荐度排序:
1. 用ObjectId自带的equals()方法(最推荐)
Mongoose的ObjectId对象内置了equals()方法,专门用来比较两个ObjectId是否相等,它会直接对比ID的实际值,而不是对象引用:
if (req.body.players_list.some((player) => { return player._id.equals(req.user._id); })) { // 用户已在players_list中,执行你的逻辑 }
另外这里用some()代替了filter(),因为some()只要找到第一个匹配项就会停止遍历,比filter()生成整个数组再判断长度要高效得多。
2. 转成字符串后比较
如果更习惯字符串操作,可以把两个ID都转成字符串再用===比较:
if (req.body.players_list.some((player) => { return player._id.toString() === req.user._id.toString(); })) { // 用户已在列表中 }
3. 提前在查询时处理(可选优化)
如果你是从数据库查询Game文档时用了populate('players_list'),那players_list里是完整的User对象;如果没populate,players_list里就是ObjectId实例。不管哪种情况,上面的两种方法都能生效。如果想提前简化,也可以在查询Game的时候,把players_list的_id转成字符串存储,但一般没必要,用前两种方法更直接。
内容的提问来源于stack exchange,提问作者darbulix

