Instance hooks

The following hooks will emit whenever you're editing a single object

  1. beforeValidate
  2. afterValidate or validationFailed
  3. beforeCreate / beforeUpdate / beforeSave / beforeDestroy
  4. afterCreate / afterUpdate / afterSave / afterDestroy
  1. // ...define ...
  2. User.beforeCreate(user => {
  3. if (user.accessLevel > 10 && user.username !== "Boss") {
  4. throw new Error("You can't grant this user an access level above 10!")
  5. }
  6. })

This example will return an error:

  1. User.create({username: 'Not a Boss', accessLevel: 20}).catch(err => {
  2. console.log(err); // You can't grant this user an access level above 10!
  3. });

The following example would return successful:

  1. User.create({username: 'Boss', accessLevel: 20}).then(user => {
  2. console.log(user); // user object with username as Boss and accessLevel of 20
  3. });

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:

  1. beforeBulkCreate(instances, options)
  2. beforeBulkUpdate(options)
  3. beforeBulkDestroy(options)
  4. afterBulkCreate(instances, options)
  5. afterBulkUpdate(options)
  6. 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.

  1. Model.destroy({ where: {accessLevel: 0}, individualHooks: true});
  2. // Will select all records that are about to be deleted and emit before- + after- Destroy on each instance
  3. Model.update({username: 'Toni'}, { where: {accessLevel: 0}, individualHooks: true});
  4. // 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.

  1. Model.beforeBulkCreate((records, {fields}) => {
  2. // records = the first argument sent to .bulkCreate
  3. // fields = one of the second argument fields sent to .bulkCreate
  4. })
  5. Model.bulkCreate([
  6. {username: 'Toni'}, // part of records argument
  7. {username: 'Tobi'} // part of records argument
  8. ], {fields: ['username']} // options parameter
  9. )
  10. Model.beforeBulkUpdate(({attributes, where}) => {
  11. // where - in one of the fields of the clone of second argument sent to .update
  12. // attributes - is one of the fields that the clone of second argument of .update would be extended with
  13. })
  14. Model.update({gender: 'Male'} /*attributes argument*/, { where: {username: 'Tom'}} /*where argument*/)
  15. Model.beforeBulkDestroy(({where, individualHooks}) => {
  16. // individualHooks - default of overridden value of extended clone of second argument sent to Model.destroy
  17. // where - in one of the fields of the clone of second argument sent to Model.destroy
  18. })
  19. 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.

  1. // Bulk updating existing users with updateOnDuplicate option
  2. Users.bulkCreate([
  3. { id: 1, isMember: true },
  4. { id: 2, isMember: false }
  5. ], {
  6. updateOnDuplicate: ['isMember']
  7. });
  8. User.beforeBulkCreate((users, options) => {
  9. for (const user of users) {
  10. if (user.isMember) {
  11. user.memberSince = new Date();
  12. }
  13. }
  14. // Add memberSince to updateOnDuplicate otherwise the memberSince date wont be
  15. // saved to the database
  16. options.updateOnDuplicate.push('memberSince');
  17. });