Strapi 5:如何在beforeUpdate钩子获取更新前原始数据并区分更新与发布
关于Strapi 5 beforeUpdate钩子获取原始数据及区分更新/发布的问题
问题背景
我在使用Strapi 5,需要在beforeUpdate生命周期钩子中获取条目更新前的原始数据,用来和新数据对比执行相关逻辑。
现有代码示例
import orderEmailService from '../../services/order-email'; export default { async beforeUpdate(event) { const { data, where, select, populate } = event.params; // 尝试从数据库获取原始数据 const oldData = await strapi.db.query('api::order.order').findOne({ where, populate: true }); console.log('oldData', oldData); }, async afterUpdate(event) { const { result } = event; const newStatus = result?.orderStatus?.orderStatus; const userId = result?.userId; if (userId && newStatus) { await orderEmailService.sendOrderStatusUpdateEmail({ userId, orderId: result.id, newStatus, }); } }, };
遇到的问题
- 在
beforeUpdate钩子中用findOne查询数据库,返回的是更新后的数据,而非预期的更新前原始数据,和官方文档描述不符。 - 尝试在
afterUpdate钩子中用publishedAt区分保存草稿和发布操作,但event.params.status为undefined,无法可靠区分两种动作。
已尝试的方案
- 在
beforeUpdate中直接查询数据库获取原始数据,结果不符合预期; - 在
afterUpdate中通过publishedAt检测发布操作,但保存草稿时钩子也会触发; - 查阅官方文档及相关讨论,未找到明确解决方法。
解决方案
1. 正确在beforeUpdate中获取原始数据
Strapi 5的beforeUpdate钩子执行时,数据库事务已启动,直接查询会读取到未提交的修改。解决方法是使用非事务查询绕过当前事务:
async beforeUpdate(event) { const { data, where, populate } = event.params; // 方法一:通过禁用事务参数获取原始数据 const oldData = await strapi.db.query('api::order.order').findOne({ where, populate, transaction: null // 禁用当前事务 }); // 方法二:使用raw查询直接操作数据库 // const [oldData] = await strapi.db.connection.raw('SELECT * FROM orders WHERE id = ?', [where.id]); console.log('原始数据:', oldData); }
2. 区分更新(保存草稿)与发布动作
方式一:使用专用发布钩子
Strapi 5对发布操作提供了专属钩子,无需在通用更新钩子中判断:
- 保存草稿:仅触发
beforeUpdate/afterUpdate - 发布操作:会额外触发
beforePublish/afterPublish钩子
将发布相关逻辑移到专属钩子中:
async afterPublish(event) { const { result } = event; const newStatus = result?.orderStatus?.orderStatus; const userId = result?.userId; if (userId && newStatus) { await orderEmailService.sendOrderStatusUpdateEmail({ userId, orderId: result.id, newStatus, }); } }
方式二:在beforeUpdate中对比publishedAt状态
结合原始数据,通过publishedAt的变化判断动作类型:
async beforeUpdate(event) { const { data, where, populate } = event.params; const oldData = await strapi.db.query('api::order.order').findOne({ where, populate, transaction: null }); // 判断是否为发布操作:从无publishedAt变为有值 const isPublishing = !oldData.publishedAt && data.publishedAt; // 判断是否为更新草稿:publishedAt保持为空,或从已发布变回草稿 const isUpdatingDraft = (oldData.publishedAt === null) || (oldData.publishedAt && !data.publishedAt); if (isPublishing) { // 执行发布专属逻辑 } else if (isUpdatingDraft) { // 执行草稿更新逻辑 } }
3. 简便方案:检查event.previousState(版本依赖)
部分Strapi 5版本中,beforeUpdate的event对象会直接携带previousState字段,包含更新前的原始数据,可直接使用:
async beforeUpdate(event) { const oldData = event.previousState; console.log('原始数据:', oldData); }
建议先测试你的Strapi版本是否支持该字段,这是最简便的实现方式。
内容的提问来源于stack exchange,提问作者YouInWeb
相关产品推荐
相关产品推荐

