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
相关产品推荐
相关产品推荐

