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

Node.js操作MongoDB报错user.save is not a function解决方法

报错原因
  • 核心触发原因:你当前封装的db.findOne()方法返回的是从MongoDB读取到的普通JavaScript对象,不是Mongoose等ODM库的文档实例,普通对象本身没有挂载save()实例方法,调用时自然会抛出user.save() is not a function错误。
  • 附带逻辑隐患:
    • 代码先判断if(user.accessToken!=''),之后才判断if(!user),如果findOne没查到匹配用户,user值为null,访问null.accessToken会直接触发空指针报错,根本走不到后续的空值判断分支。
    • 开头let user = await db.aggregate('USER', query);属于冗余无效代码:query变量未定义,且后续马上重新给user赋值为findOne的查询结果,这行执行本身就存在报错风险。
修复方案
  • 调整判断顺序:先校验用户是否存在,再处理旧token失效逻辑,避免空指针异常。
  • 放弃调用save()方法,统一使用你自己封装的db层静态更新方法(和代码中已使用的findOneAndUpdate、create保持同一套调用逻辑),直接通过更新语句将旧token置空,不需要先查询文档再调用实例方法保存,同时还能减少一次数据库交互。
  • 删除开头冗余的aggregate无效代码。
  • 调整响应返回顺序:等所有数据库更新操作完成后再返回接口响应,避免响应发出后更新操作执行失败的一致性问题。

修复后的完整可运行代码如下:

export const signin = async (req, res) => {
  try {
    const code = req.body.code;
    console.log(code + "code");

    const profile = await verifyIdToken(code);
    console.log(profile + "signinuser");
    const newUser = {
      uid: profile.uid,
      name: profile.name,
      email: profile.email,
      paymentUpdated: false,
      isLoggedIn: true,
      userBrowser: req.headers["user-agent"]
    };

    // 删除冗余的aggregate查询,直接查询目标用户
    let user = await db.findOne('USER', {email: newUser.email});
    
    // 先判断用户存在,再处理旧token失效逻辑
    if (user) {
      if (user.accessToken !== '') {
        // 复用已封装的findOneAndUpdate方法置空旧token,无需调用save()
        await db.findOneAndUpdate('USER', {email: newUser.email}, {
          $set: {
            accessToken: '',
            refreshToken: ''
          }
        });
        console.log("旧token已失效");
      }
    } else {
      // 查无对应用户时创建新用户
      user = await db.create('USER', newUser);
    }

    const token = generateToken(user);
    // 更新用户accessToken为新生成的有效token
    await db.findOneAndUpdate('USER', { email: newUser.email }, {$set:{accessToken: token}})
    // 所有数据库操作完成后返回响应
    res.status(200).json({ user, token });

  } catch (err) {
    console.log(err)
    res.status(500).json({ message: "Something went wrong" });
  }
};

补充说明:如果你后续直接使用原生Mongoose的findOne方法且需要调用save(),请确认查询时没有添加.lean()选项——添加.lean()后返回的结果就是普通JS对象,不会携带save()等实例方法。从你当前db.xxx方法第一个参数传集合名字符串的调用形式来看,你是自行封装了一层数据库操作,默认返回普通对象,直接使用封装好的更新方法是最稳妥的方案。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 01:21:33