MongoDB findOneAndUpdate返回Promise始终resolve的原因排查
问题原因
核心问题是你对findOneAndUpdate的返回结构判断完全错误:
- 对MongoDB驱动来说,「没匹配到符合条件的文档」属于查询执行成功但无结果,不是执行错误,永远不会触发reject,只有数据库连接断了、语法写错这类底层故障才会进catch。你预期空库时方法执行失败,本身就是对方法行为的误解。
- 该方法resolve的不是匹配到的文档本身,而是一个操作结果对象,结构类似:
{ ok: 1, // 标记操作本身执行成功 value: null, // 匹配到的文档,无匹配时为null lastErrorObject: {} }
你代码里直接判断if (userDoc),这个结果对象永远是真值(哪怕value是null,对象本身转布尔也是true),所以不管有没有匹配到用户,永远会走resolve分支。
修复代码
首先修改User.activate方法,去掉多余的手动Promise包装(方法本身就返回Promise,手动包一层属于冗余写法,还容易漏捕获错误),正确判断返回结果里的文档字段:
User.activate = function(activationLink) { return usersCollection.findOneAndUpdate( { activationLink }, { $set: { isActivated: true } }, // 可选配置:返回更新后的文档,默认返回更新前的旧文档 { returnDocument: 'after' } ).then(res => { if (res.value) { return 'Your account has been activated!' } throw new Error('This account does not exist!') }) }
controller层可以按需调整状态码,让响应更符合规范,核心逻辑不用大改:
exports.activate = function(req, res){ User.activate(req.params.activationLink) .then(result => res.send(result)) .catch(e => res.status(404).send(e.message)) }
路由层代码没有问题,不需要修改。
补充说明
如果用的是旧版Mongoose驱动,findOneAndUpdate默认会直接返回匹配到的文档(无匹配返回null),但如果开启了rawResult配置,也会返回上述原生驱动的结果对象,判断逻辑保持一致即可。
内容的提问来源于stack exchange,提问作者Andrey
相关产品推荐
相关产品推荐

