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

Node.js+Multer+MongoDB实现文件编辑替换功能报错解决

文件编辑功能报错:TypeError: Cannot read property 'findByIdAndUpdate' of undefined 解决方案

问题背景

我搭建了一个支持文件上传的网站,现在想新增文件编辑功能:用户点击编辑按钮后上传新文件,替换数据库中对应的旧文件。普通文本字段可以用findByIdAndUpdate处理,但处理异步文件操作时遇到了问题,代码报错:TypeError: Cannot read property 'findByIdAndUpdate' of undefined。

现有上传代码

var storage = multer.diskStorage({
  destination: (req, file, cb) => {
    cb(null, "uploads");
  },
  filename: (req, file, cb) => {
    cb(null, file.fieldname + "-" + Date.now() + ".png");
  },
});

var upload = multer({ storage: storage });

router.use(flash())

router.get("/create", (req, res) => {
  res.render("uploadPicture", {
    items: items,
    user: req.auth,
    title: "Upload",
  });
});

router.get("/", (req, res) => {
  image.find({}, (err, items) => {
    if (err) {
      console.log(err);
      res.status(500).send("An error occurred", err);
    } else {
      res.render("uploadPicture", {
        errMsg: req.flash('image'),
        items: items,
        user: req.auth,
        title: "pictures",
      });
    }
  });
});


router.post("/upload", upload.single("image"), async (req, res, next) => {
  const { folder } = sanitize(req.body);
  var obj = {
    name: req.body.name,
    userId: req.auth.userId,
    folder: folder,
    img: {
      data: fs.readFileSync(
        path.join(__dirname, "../uploads/" + req.file.filename )
      ),
      contentType: "image/png",
    },
  };
  image.create(obj, (err, items) => {
    if (err) {
      console.log("Test")
      console.log(err);
      req.flash('image', 'Image failed to upload!')
      res.redirect("/picture")
    } else {
      console.log(obj);
      items.save();
      req.flash('image', 'Image succesfully uploaded!')
      res.redirect("/picture")
    }
  });
});

module.exports = router;

尝试的编辑代码

router.post("/edit/:id", upload.single("image"), async(req, res ) =>{
  const id = req.params.id;
  console.log(req.params.id)
  const { folder } = sanitize(req.body);
  var obj = {
    name: req.body.name,
    userId: req.auth.userId,
    folder: folder,
  };
  if(req.body.image == ""){
    console.log("nothing here")
    image.findByIdAndUpdate(id, {name: req.body.name,folder: folder,}, function(err, docs){
      if (err) {
        console.log(err);
        req.flash('image', 'Image failed to upload!')
        res.redirect("/picture")
      } else {
        console.log(obj);
        req.flash('image', 'Image succesfully uploaded!')
        res.redirect("/picture")
      }
    })
  }else{
  var image = {
      img: {
        data: fs.readFileSync(
          path.join(__dirname, "../uploads/" + req.file.filename )
        ),
        contentType: "image/png",
      },
   }
   image.findByIdAndUpdate(id, {name: req.body.name,folder: folder,image: image}, function(err, docs){
    if (err) {
      console.log(err);
      req.flash('image', 'Image failed to upload!')
      res.redirect("/picture")
    } else {
      console.log(obj);
      req.flash('image', 'Image succesfully uploaded!')
      res.redirect("/picture")
    }
  })
  }

})

报错原因

你在编辑代码的else块里,用var image声明了一个局部变量,直接覆盖了全局的Mongoose模型image。此时image变成了你定义的普通对象,自然没有findByIdAndUpdate方法,所以触发报错。

修复方案

1. 核心修复点

  • 重命名局部变量:把else块里的var image改成newImageData这类不会冲突的名字,避免覆盖模型。
  • 修正文件存在判断:原来的req.body.image == ""逻辑错误,multer上传的文件会存在req.file对象中,应该用!req.file判断用户是否未上传新文件。
  • 改用async/await优化异步逻辑:替代回调函数,让代码更清晰易维护。

2. 修正后的完整编辑代码

router.post("/edit/:id", upload.single("image"), async (req, res) => {
  try {
    const id = req.params.id;
    const { folder, name } = sanitize(req.body);
    const updateData = { name, folder };

    // 用户上传了新文件的情况
    if (req.file) {
      const newImageData = {
        img: {
          data: fs.readFileSync(path.join(__dirname, "../uploads/" + req.file.filename)),
          contentType: "image/png",
        },
      };
      // 合并新文件数据到更新对象
      Object.assign(updateData, newImageData);

      // 可选:删除服务器上的旧文件(需确保数据库存储了旧文件名)
      const oldItem = await image.findById(id);
      if (oldItem && oldItem.filename) {
        const oldFilePath = path.join(__dirname, "../uploads/" + oldItem.filename);
        fs.unlink(oldFilePath, (err) => {
          if (err) console.error("删除旧文件失败:", err);
        });
      }
    }

    // 执行数据库更新
    await image.findByIdAndUpdate(id, updateData);

    req.flash('image', '修改成功!');
    res.redirect("/picture");
  } catch (err) {
    console.error(err);
    req.flash('image', '修改失败!');
    res.redirect("/picture");
  }
});

额外建议

  • 确保Mongoose模型image已正确导入当前路由文件,无拼写错误。
  • 上传文件时建议把文件名存储到数据库(比如新增filename字段),方便后续删除旧文件。
  • 文件操作需做好错误捕获,避免因文件读写失败导致整个请求崩溃。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 08:05:14