通过PATCH请求使用Sequelize更新数据:优化结果处理方案问询
问题
我正在使用Sequelize和MySQL开发支持CRUD操作的REST API,通过控制器处理PATCH请求来更新产品字段。当前实现虽能正常运行,但希望找到更优雅的结果处理方式。
Sequelize的update方法会返回一个结果数组:Array[0]为更新操作的受影响行数(我按ID更新,理论上应为1),Array[1]包含更新详情以及所有新旧值。以下是当前的处理逻辑:
//products.controller.js //Update a single product using id (PUT/PATCH) const patch = (req, res) => { const id = req.params.id; Product.update(req.body, { where: { id }, individualHooks: true }) .then((rowsAffected) => { //Item not found if (Object.entries(rowsAffected[1]).length === 0) { res.status(404).send({ success: false, status: 404, //Not found message: `Product with id ${id} not found. Update failed.`, }); return; } //if rowsAffected[0] === 1 then success if (rowsAffected[0] === 1) { //row changed res.status(200).send({ success: true, status: 200, message: `Product updated.`, id: id, payload: req.body, }); } else { // if rowsAffected[0] !== 1 then it failed. res.status(200).send({ success: false, status: 200, //Not Modified message: `No fields have changed. Product not updated.`, }); } }) .catch((err) => { res.status(500).send({ success: false, status: 500, message: err.message || "Something went wrong while updating the product.", }); }); }
目前通过判断Object.entries(rowsAffected[1]).length === 0来检测产品是否存在,这种拆解update返回值的方式不够优雅,希望得到更优方案。
优化方案
方案1:先查询再更新,逻辑直观易懂
先通过findByPk确认产品存在,再执行更新操作,完全避免解析update返回的复杂结构:
const patch = async (req, res) => { const { id } = req.params; try { // 先验证产品是否存在 const product = await Product.findByPk(id); if (!product) { return res.status(404).send({ success: false, status: 404, message: `Product with id ${id} not found. Update failed.`, }); } // 执行更新 const [updatedRows] = await Product.update(req.body, { where: { id }, individualHooks: true }); if (updatedRows === 1) { return res.status(200).send({ success: true, status: 200, message: `Product updated.`, id, payload: req.body, }); } else { // 改用304更符合HTTP无变更的语义 return res.status(304).send({ success: false, status: 304, message: `No fields have changed. Product not updated.`, }); } } catch (err) { res.status(500).send({ success: false, status: 500, message: err.message || "Something went wrong while updating the product.", }); } };
优势
- 逻辑清晰直接,无需解析
update返回的嵌套对象 - 使用
async/await替代Promise链式调用,代码可读性更高
方案2:优化update返回值处理,利用Sequelize选项
如果不想额外查询,可以通过解构赋值简化返回值操作,结合returning和plain选项让结果更简洁(MySQL需确保版本支持returning):
const patch = async (req, res) => { const { id } = req.params; try { // 解构返回值,同时获取更新后的实例 const [updatedRows, [updatedProduct]] = await Product.update(req.body, { where: { id }, individualHooks: true, returning: true, // 返回更新后的产品实例 plain: true // 转为普通JS对象,而非Sequelize实例 }); // 直接通过实例是否存在判断产品是否找到 if (!updatedProduct) { return res.status(404).send({ success: false, status: 404, message: `Product with id ${id} not found. Update failed.`, }); } if (updatedRows === 1) { return res.status(200).send({ success: true, status: 200, message: `Product updated.`, id, payload: updatedProduct, // 返回完整更新后数据,更友好 }); } else { return res.status(304).send({ success: false, status: 304, message: `No fields have changed. Product not updated.`, }); } } catch (err) { res.status(500).send({ success: false, status: 500, message: err.message || "Something went wrong while updating the product.", }); } };
优势
- 用解构赋值
const [updatedRows, [updatedProduct]]替代索引取值,代码更简洁 - 通过
returning: true直接获取更新后的实例,无需额外查询 - 用
!updatedProduct判断产品存在性,比解析对象长度更直观
额外优化建议
- HTTP状态码:无字段变更时返回
304 Not Modified,更符合HTTP语义 - 响应数据:返回更新后的完整产品数据,而非仅客户端提交的
req.body,前端能更清晰了解更新结果 - 错误处理:统一用
try/catch包裹异步操作,避免Promise链式调用的嵌套问题
内容的提问来源于stack exchange,提问作者Kenny
相关产品推荐
相关产品推荐

