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

Mongoose findByIdAndUpdate返回正常但MongoDB数据未更新

问题原因

你代码里有4个直接导致数据无法写入MongoDB的错误:

  • 路由用了GET方法:常规HTTP服务的Body解析中间件默认不会处理GET请求的请求体,你代码里取的req.body.username实际是undefined;且好友添加属于数据写操作,本身就应该用POST/PUT类写请求方法,不能用GET。
  • 路由处理函数定义错误:你写的处理函数既没有加async关键字,也没有接收req、res形参。函数内的await在非async函数里无法生效,直接调用req/res会触发引用错误,整个更新逻辑根本没有正常执行到数据库写入步骤。
  • findByIdAndUpdate缺少必填配置:这个Mongoose方法默认返回更新前的原始文档,且当查询条件传入的是从中间件查出来的Mongoose文档实例时,部分版本下只会修改内存中的文档对象,不会实际向MongoDB发送写入命令——这就是你控制台打印u能看到新好友数据,但数据库里没变化的核心原因,你看到的是内存里临时修改的对象,不是数据库持久化后的结果。
  • 鉴权中间件没有错误捕获:jwt.verify遇到过期、伪造的token会直接抛出异常,没有捕获的话会直接中断请求,根本走不到后续更新逻辑。
修复方案
  1. 把路由请求方法从GET改为POST,给路由处理函数加上async标记,补全req、res形参
  2. 给findByIdAndUpdate传入第三个配置参数,指定返回更新后的文档、写入时执行Schema校验
  3. 给鉴权中间件加上异常捕获,提前拦截无效token
  4. 确认Express服务在路由注册前已经挂载了JSON请求体解析中间件

修复后的路由代码

// 注意请求方法改为POST,处理函数加async,补全req、res参数
app.post("/add", userController.auth, async (req, res) => {
  try {
    const updatedUser = await users.findByIdAndUpdate(
      req.user._id,
      { $push: { friends: { name: req.body.username } } },
      // 核心配置,缺一不可
      {
        new: true, // 返回更新完成后的新文档,而非更新前的旧文档
        runValidators: true // 写入时强制执行Schema定义的校验规则
      }
    )
    console.log(updatedUser);
    return res.status(201).json({
      friends: updatedUser.friends
    })
  } catch (err) {
    return res.status(500).json({ msg: "好友添加失败", error: err.message })
  }
})

修复后的鉴权中间件

exports.auth = async (req, res, next) => {
  try {
    const token = req.headers["token"];
    if (!token) return res.status(401).json({ msg: "请先登录" })
    
    const verifyToken = jwt.verify(token, "i_put_my_secret_here")
    const currentUser = await users.findOne({ _id: verifyToken.id }).select("-password")
    if (!currentUser) return res.status(401).json({ msg: "用户身份无效" })
    
    req.user = currentUser
    next()
  } catch (err) {
    return res.status(401).json({ msg: "鉴权失败,请重新登录", error: err.message })
  }
}

前置配置检查

确认你的Express入口文件中,在所有路由注册之前已经挂载了内置的JSON解析中间件,否则req.body会一直是undefined:

const express = require('express')
const app = express()
// 必须在路由注册前挂载
app.use(express.json())

// 后续再写app.use('/xxx', xxxRouter)这类路由注册代码

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 09:06:20