Instance hooks
The following hooks will emit whenever you're editing a single object
beforeValidate
afterValidate or validationFailed
beforeCreate / beforeUpdate / beforeSave / beforeDestroy
afterCreate / afterUpdate / afterSave / afterDestroy
// ...define ...
User.beforeCreate(user => {
if (user.accessLevel > 10 && user.username !== "Boss") {
throw new Error("You can't grant this user an access level above 10!")
}
})
This example will return an error:
User.create({username: 'Not a Boss', accessLevel: 20}).catch(err => {
console.log(err); // You can't grant this user an access level above 10!
});
The following example would return successful:
User.create({username: 'Boss', accessLevel: 20}).then(user => {
console.log(user); // user object with username as Boss and accessLevel of 20
});
Model hooks
Sometimes you'll be editing more than one record at a time by utilizing the bulkCreate, update, destroy
methods on the model. The following will emit whenever you're using one of those methods:
beforeBulkCreate(instances, options)
beforeBulkUpdate(options)
beforeBulkDestroy(options)
afterBulkCreate(instances, options)
afterBulkUpdate(options)
afterBulkDestroy(options)
If you want to emit hooks for each individual record, along with the bulk hooks you can pass individualHooks: true
to the call.
WARNING: if you use individual hooks, all instances that are updated or destroyed will get loaded into memory before your hooks are called. The number of instances Sequelize can handle with individual hooks is limited by available memory.
Model.destroy({ where: {accessLevel: 0}, individualHooks: true});
// Will select all records that are about to be deleted and emit before- + after- Destroy on each instance
Model.update({username: 'Toni'}, { where: {accessLevel: 0}, individualHooks: true});
// Will select all records that are about to be updated and emit before- + after- Update on each instance
The options
argument of hook method would be the second argument provided to the corresponding method or itscloned and extended version.
Model.beforeBulkCreate((records, {fields}) => {
// records = the first argument sent to .bulkCreate
// fields = one of the second argument fields sent to .bulkCreate
})
Model.bulkCreate([
{username: 'Toni'}, // part of records argument
{username: 'Tobi'} // part of records argument
], {fields: ['username']} // options parameter
)
Model.beforeBulkUpdate(({attributes, where}) => {
// where - in one of the fields of the clone of second argument sent to .update
// attributes - is one of the fields that the clone of second argument of .update would be extended with
})
Model.update({gender: 'Male'} /*attributes argument*/, { where: {username: 'Tom'}} /*where argument*/)
Model.beforeBulkDestroy(({where, individualHooks}) => {
// individualHooks - default of overridden value of extended clone of second argument sent to Model.destroy
// where - in one of the fields of the clone of second argument sent to Model.destroy
})
Model.destroy({ where: {username: 'Tom'}} /*where argument*/)
If you use Model.bulkCreate(…)
with the updateOnDuplicate
option, changes made in the hook to fields that aren't given in the updateOnDuplicate
array will not be persisted to the database. However it is possible to change the updateOnDuplicate option inside the hook if this is what you want.
// Bulk updating existing users with updateOnDuplicate option
Users.bulkCreate([
{ id: 1, isMember: true },
{ id: 2, isMember: false }
], {
updateOnDuplicate: ['isMember']
});
User.beforeBulkCreate((users, options) => {
for (const user of users) {
if (user.isMember) {
user.memberSince = new Date();
}
}
// Add memberSince to updateOnDuplicate otherwise the memberSince date wont be
// saved to the database
options.updateOnDuplicate.push('memberSince');
});