Sequelize操作Postgres分类表时插入更新自动调整viewOrder排序字段方案
Sequelize 实现分类排序位调整方案
所有操作均需包在 Sequelize 事务中执行,避免并发操作导致 viewOrder 唯一约束冲突,保证数据一致性。
1. 新增记录时插入指定 viewOrder 位置
逻辑步骤:
- 校验传入的目标 viewOrder 为正整数
- 开启事务
- 批量更新所有
viewOrder >= 目标插入值的记录,将其 viewOrder 值+1 - 插入新的分类记录,viewOrder 为目标值
- 提交事务,异常时回滚
代码示例:
const { Op } = require('sequelize'); async function addCategory(name, targetViewOrder) { const transaction = await sequelize.transaction(); try { // 把大于等于目标排序位的所有现有记录排序+1 await Category.increment('viewOrder', { where: { viewOrder: { [Op.gte]: targetViewOrder } }, transaction }); // 插入新分类记录 const newCategory = await Category.create({ name, viewOrder: targetViewOrder }, { transaction }); await transaction.commit(); return newCategory; } catch (err) { await transaction.rollback(); throw err; } }
2. 更新记录时调整 viewOrder 位置
逻辑步骤:
- 先查询要修改的目标记录,获取原有的 viewOrder 值
oldOrder - 校验新的
newOrder为正整数,若newOrder === oldOrder直接返回无需修改 - 开启事务
- 分两种情况处理区间内其他记录的排序:
- 若
newOrder < oldOrder:将viewOrder >= newOrder 且 viewOrder < oldOrder的所有记录的 viewOrder +1 - 若
newOrder > oldOrder:将viewOrder > oldOrder 且 viewOrder <= newOrder的所有记录的 viewOrder -1
- 若
- 更新目标记录的 viewOrder 为
newOrder - 提交事务,异常时回滚
代码示例:
const { Op } = require('sequelize'); async function updateCategoryViewOrder(categoryId, newOrder) { const transaction = await sequelize.transaction(); try { // 查询目标记录原有排序值 const targetCategory = await Category.findByPk(categoryId, { transaction }); if (!targetCategory) throw new Error('分类不存在'); const oldOrder = targetCategory.viewOrder; // 排序未变化直接返回 if (newOrder === oldOrder) { await transaction.commit(); return targetCategory; } // 调整区间内其他记录的排序 if (newOrder < oldOrder) { await Category.increment('viewOrder', { where: { viewOrder: { [Op.gte]: newOrder, [Op.lt]: oldOrder } }, transaction }); } else { await Category.decrement('viewOrder', { where: { viewOrder: { [Op.gt]: oldOrder, [Op.lte]: newOrder } }, transaction }); } // 更新目标记录的排序值 await targetCategory.update({ viewOrder: newOrder }, { transaction }); await transaction.commit(); return targetCategory; } catch (err) { await transaction.rollback(); throw err; } }
注意事项
- 若插入的目标 viewOrder 大于当前表中最大的 viewOrder 值,无需执行批量更新逻辑,直接插入即可,可自行添加判断优化性能
- 生产环境建议对操作加分布式锁,避免高并发下出现唯一约束冲突
- 可在 Model 层添加
viewOrder的校验规则,确保入库值为正整数,和前端校验做双重保障
内容的提问来源于stack exchange,提问作者Rafael
相关产品推荐
相关产品推荐

