MongoDB同一文档同时使用$set与$pull操作失效问题咨询
问题原因分析
- $pull 语法使用错误:当同时执行三类操作时,待删除的图片参数
imagesDelete为数组格式,你原写法{"filename": imagesDelete }要求MongoDB匹配filename字段完全等于整个数组的图片条目,不存在符合条件的数据,会导致删除操作失效。部分MongoDB版本会将这类无效匹配的更新请求判定为非法,连带同批次的$set字段修改也不执行,最终整个更新逻辑异常。 - Cloudinary 删除未做异步等待:你使用回调方式调用Cloudinary删除接口,代码不会等待删除完成就直接执行后续数据库操作,若删除过程报错,回调内的响应返回逻辑会因为主请求已经响应完成,触发「无法重复设置响应头」的异常,直接导致接口报错。
修复方案
核心修改点
- 动态构造更新对象,当存在待删除图片时,使用
$in匹配数组内的所有待删除文件名 - 将Cloudinary删除操作改为Promise异步等待调用,避免回调导致的时序问题
- 统一处理单张/多张删除的逻辑,无需单独判断字符串/数组类型
- 新增上传图片判空逻辑,避免无新图片上传时报错
修复后完整代码
exports.editarProductoUser = async (req, res, next) => { // 校验参数错误 const errors = validationResult(req); if (!errors.isEmpty()) { return res.status(400).json({ errors: errors.array() }); } console.log(req.body); const { imagesDelete, title, categoria, subCategoria, price, description, contacto } = req.body; try { // 校验商品是否存在 const productoTest = await Producto.findById(req.params.id); if (!productoTest) { console.log("hay un error en edicion"); return res.status(404).json({ msg: "Producto no encontrado" }); } // 校验操作权限 if (productoTest.author.toString() !== req.user.id) { return res.status(401).json({ msg: "No Autorizado para Editar" }); } // 处理Cloudinary图片删除 if (imagesDelete !== undefined) { const deleteList = Array.isArray(imagesDelete) ? imagesDelete : [imagesDelete]; for (let filename of deleteList) { try { await cloudinary.uploader.destroy(filename); } catch (err) { console.log(err); return res.status(400).json({ ok: false, message: "Error deleting file", errors: err, }); } } } // 动态构造更新语句 const updateOps = { $set: { title, categoria, subCategoria, price, description, contacto } }; if (imagesDelete !== undefined) { const deleteList = Array.isArray(imagesDelete) ? imagesDelete : [imagesDelete]; updateOps.$pull = { images: { filename: { $in: deleteList } } }; } // 执行更新操作 const producto = await Producto.findByIdAndUpdate( req.params.id, updateOps, { new: true } ); // 新增上传的图片 if (req.files?.length) { const images = req.files.map((f) => ({ url: f.path, filename: f.filename, })); producto.images.push(...images); await producto.save(); } res.json({ producto }); } catch (error) { console.log(error); res.status(500).send("Hubo un Error"); } };
内容的提问来源于stack exchange,提问作者ddaudiosolutions
相关产品推荐
相关产品推荐

