MongoDB更新以$开头的字符串字段时字段被删除如何解决
问题原因
你遇到的问题是MongoDB更新管道的字段引用机制导致的:当你给updateOne传入数组类型的第二个参数时,MongoDB会将其识别为更新管道执行,管道内$set的字段值如果以$开头,会被默认解析为对同文档其他字段的引用,而非普通字符串。bcrypt生成的哈希恰好以$2a$/$2b$这类前缀开头,MongoDB找不到对应名称的字段,就会将hash字段赋值为null,最终表现为字段被移除。
解决方案
方案1:改用普通更新语法(最推荐)
如果你的更新逻辑不需要用到管道的复杂计算能力,直接去掉第二个参数的数组包裹,使用普通更新语法即可。普通更新模式下不会解析值内的$为字段引用:
const hash = await bcrypt.hash(password, 10); // 去掉数组包裹,直接传更新对象 collection.updateOne({ email }, { $set: { hash } });
方案2:管道模式下使用$literal标记字面量
如果你确实需要使用更新管道完成复杂逻辑,可以用$literal操作符包裹哈希值,显式告诉MongoDB该值是普通字面量,不需要解析为字段引用:
const hash = await bcrypt.hash(password, 10); collection.updateOne({ email }, [ { $set: { hash: { $literal: hash } } } ]);
两种方案都可以正常存储带$前缀的bcrypt哈希,后续验证密码时直接取出字段调用bcrypt.compare即可,不需要额外转义处理。
内容的提问来源于stack exchange,提问作者kgommers
相关产品推荐
相关产品推荐

