You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Node.js+React中Mongoose更新文档失败及返回异常问题

用户注册流程中的MongoDB文档更新异常问题

我在React+Node.js Express+Mongoose的项目里做用户注册流程,更新用户文档时碰到了问题:

  • 调用updateOne返回acknowledged:false,文档完全没更新
  • 改用findOneAndUpdate并设置new:true,返回的还是原始文档,不是更新后的

相关代码如下:

后端注册路由代码

router.post('/register', async (req, res) => {

   const {  name, username, email, phoneNumber, password } = req.body;

    try {

        let user = await User.findOne({ email: email });

        if(user) {
           return res.json({
               errors: [{ msg: "User already exists." }],

           });
        }

        const avatar = gravatar.url(email, { s: '200', r: 'pg', d: 'mm'})
        user = new User({ name, username, email, phoneNumber, avatar, password});

        const salt = await bcrypt.genSalt(10);
        user.password = await bcrypt.hash(password, salt);

        user.save().then( async (result) => {

            if(result) {

                const payload = {
                    user: {
                        id: user.id
                    }
                }
                jwt.sign(payload, "secret", {
                    expiresIn: 3600
                }, (err, token) => {
                    if(err) {
                        throw err;
                    } else {
                        res.json({
                            token: token,

                        });
                    }
                });

            } else {
                return res.json({ errors: [{ msg: "Registration Error." }] });
            }
        });

    } catch (err) {
        console.error(err.message);
        res.status(500).send("Server Error");
    }
}); 

router.post("/verification/send", async (req, res) => {

    const { email, name } = req.body;
    
    let verify_token = new Buffer.from(JSON.stringify({"email": email,})).toString("base64");
    
    await User.update(
        { email: email }, {
            $set: {
                verificationToken: verify_token,
            },

        }, {
            new: true,
        }).then((data) => {

                console.log(data)// logs acknowledged:false

                let emailObject = {
                    from: {
                        name: "name",
                        email:"info@info.com",
                    },

                    to: {
                        name: name,
                        email: email
                    },
                    subject: 'Email Verification',
                    html: "myhtmlfile",
                  
                };
                sgMail.send(emailObject).then(function (data) {
                    res.status(200).json({
                        msg: "Email sent successfully",
                        result: data
                    });
                }, function (error) {
                    console.error(error.message);
                    res.status(400).json({
                        msg: "Email not sent",
                    });
                });

    }).catch((e) => {
        console.error(e);
        res.status(500).send("Server Error");
    });
});

React前端Register.js代码

axios.post("/register", data).then( async (response) => {
      console.log(response);
      if(response.data.statusCode === 200) {
        await dispatch({type: ACTION_TYPES.REGISTER_SUCCESS, payload: response.data});

        axios.post("/verification/send", emailData).then((result) => {
          console.log(result)
          if(result) {
            Toast.fire({
              icon: "success",
              title: "We have sent an email to your inbox",
            });
          }
        });
      } else if(response.data.statusCode === 403) {
        await dispatch({ type: ACTION_TYPES.REGISTER_ERROR, payload: response.data.errors[0].msg });
      }
    }).catch((e) => {
      console.log(e)
      console.error(e.message)
    })

问题分析与修复方案

核心问题1:update方法参数错误

你在/verification/send路由里用了User.update(),这个方法在Mongoose中不支持new:true参数,它的返回值是更新结果统计(比如nModified),不是文档。而acknowledged:false通常意味着查询条件没匹配到任何文档,或者数据库操作存在异常。

核心问题2:混用async/await和.then()

代码里同时混用await和.then(),容易导致逻辑时序混乱,比如注册路由里user.save().then(...)没有和外层async正确结合,可能引发异步执行顺序问题。

修复步骤:

  1. 替换update为findOneAndUpdate
    在/verification/send路由中改用findOneAndUpdate,确保参数配置正确:

    • new:true:指定返回更新后的文档
    • runValidators:true:更新时触发Schema验证(可选但推荐)
    • 先确认查询条件能匹配到目标文档

    修改后的代码:

    router.post("/verification/send", async (req, res) => {
        const { email, name } = req.body;
        const verify_token = Buffer.from(JSON.stringify({ email })).toString("base64");
    
        try {
            const updatedUser = await User.findOneAndUpdate(
                { email },
                { $set: { verificationToken: verify_token } },
                { new: true, runValidators: true }
            );
    
            if (!updatedUser) {
                return res.status(404).json({ msg: "User not found" });
            }
    
            console.log("Updated user:", updatedUser);
    
            const emailObject = {
                from: { name: "name", email: "info@info.com" },
                to: { name, email },
                subject: 'Email Verification',
                html: "myhtmlfile",
            };
    
            await sgMail.send(emailObject);
            res.status(200).json({ msg: "Email sent successfully" });
        } catch (e) {
            console.error(e);
            res.status(500).send("Server Error");
        }
    });
    
  2. 统一使用async/await,避免混用.then()
    注册路由里的user.save()改成await写法,让逻辑更清晰:

    router.post('/register', async (req, res) => {
        const { name, username, email, phoneNumber, password } = req.body;
    
        try {
            let user = await User.findOne({ email });
            if (user) {
                return res.json({ errors: [{ msg: "User already exists." }] });
            }
    
            const avatar = gravatar.url(email, { s: '200', r: 'pg', d: 'mm' });
            user = new User({ name, username, email, phoneNumber, avatar, password });
    
            const salt = await bcrypt.genSalt(10);
            user.password = await bcrypt.hash(password, salt);
    
            await user.save();
    
            const payload = { user: { id: user.id } };
            jwt.sign(payload, "secret", { expiresIn: 3600 }, (err, token) => {
                if (err) throw err;
                res.json({ token });
            });
        } catch (err) {
            console.error(err.message);
            res.status(500).send("Server Error");
        }
    });
    
  3. 检查前端请求的emailData正确性
    确保前端传给/verification/send的emailData里的邮箱和注册时完全一致,没有大小写或拼写错误,否则查询条件匹配不到文档,更新自然不会生效。

额外注意点

  • 确保Mongoose版本为最新,旧版本可能存在方法参数兼容问题
  • 可以在更新前先调用User.findOne({ email })确认用户存在,避免无效更新
  • 详细捕获数据库操作错误,打印完整错误信息便于排查

内容的提问来源于stack exchange,提问作者motionless570

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 23:05:32