Mongoose findByIdAndUpdate未按预期工作:空请求体未触发必填验证
问题原因与解决方案
为什么空req.body更新不会触发必填验证?
Mongoose的required验证规则默认只在两种场景下生效:
- 创建新文档时(比如调用
save()、create()),会校验所有必填字段是否存在。 - 修改某个字段时,仅对被修改的字段执行其对应的
required验证。
你用findByIdAndUpdate传入空req.body时,没有对任何字段做修改操作,所以Mongoose不会去校验username和password的required规则。哪怕设置了runValidators: true,这个选项也只是让Mongoose对你传入的更新字段执行验证,而非强制检查所有必填字段的完整性。
解决办法
1. 手动校验请求体(最直接)
在执行数据库更新前,先检查请求体是否包含必要字段:
router.put("/users/:id", async (req, res) => { // 手动校验必填字段 if (!req.body.username || !req.body.password) { return res.status(400).send({ error: "用户名和密码为必填项" }); } try { const user = await User.findByIdAndUpdate(req.params.id, req.body, { new: true, runValidators: true, }); if (!user) { return res.status(404).send(); } res.status(200).send(user); } catch (error) { res.status(400).send(error); } });
2. 开启全字段验证
如果需要强制Mongoose对文档所有字段(包括未修改的)执行验证,可添加validateModifiedOnly: false选项:
const user = await User.findByIdAndUpdate(req.params.id, req.body, { new: true, runValidators: true, validateModifiedOnly: false });
注意:这种方式仅检查文档当前的字段是否符合required规则,如果原文档的username和password本来就存在,空body更新不会报错;只有当原文档的必填字段缺失时才会触发验证。
3. 用中间件校验更新内容
在schema中添加pre('updateOne')中间件,拦截空内容的更新请求:
userSchema.pre('updateOne', function(next) { const update = this.getUpdate(); // 检查是否传入了需要更新的必填字段 if (!update.$set || (!update.$set.username && !update.$set.password)) { return next(new Error('更新必须提供用户名或密码')); } next(); });
findByIdAndUpdate会触发updateOne中间件,这样就能在更新操作执行前完成校验。
内容的提问来源于stack exchange,提问作者Cody
相关产品推荐
相关产品推荐

