'Sequelize.js onDelete: 'cascade' is not deleting records sequelize

I am having Product table with following columns [id, name, CategoryId] and Category table with [id, name]

Product Model:-

module.exports = function(sequelize, DataTypes) {
  var Product = sequelize.define('Product', {
    name: DataTypes.STRING
  }, {
    associate: function(models) {
      Product.belongsTo(models.Category);
    }
  });
  return Product
}

Category Model:-

module.exports = function(sequelize, DataTypes) {
  var Category = sequelize.define('Category', {
    name: { type: DataTypes.STRING, allowNull: false }
  }, {
    associate: function(models) {
      Category.hasMany(models.Product, { onDelete: 'cascade' });
    }
  });
  return Category
}

when I delete category, it deletes category only not the corresponding products associated with it. I don't know why this is happening?

update: Sequelize Version sequelize 1.7.0

================================================================================ Answer(How this I have fixed.):-

I accomplished this by adding constraint on database using Alter command, as Add Foreign Key Constraint through migration is an open bug in sequelize.

ALTER TABLE "Products"
ADD CONSTRAINT "Products_CategoryId_fkey" FOREIGN KEY ("CategoryId")
REFERENCES "Categories" (id) MATCH SIMPLE
ON DELETE CASCADE


Solution 1:[1]

I believe you are supposed to put the onDelete in the Category model instead of in the products model.

module.exports = function(sequelize, DataTypes) {
  var Category = sequelize.define('Category', {
    name: { type: DataTypes.STRING, allowNull: false }
  }, {
    associate: function(models) {
      Category.hasMany(models.Product, { onDelete: 'cascade' });
    }
  });
  return Category
}

Solution 2:[2]

I'm on Sequelize 4.38.0.

I had to put onDelete: 'CASCADE' not only on the association definition, but as well in the migration file.

// in models/user.js
User.associate = models => {
  User.belongsTo(models.Organization, {
    foreignKey: { name: 'organizationId', allowNull: true },
    onDelete: 'CASCADE',
  })
}

// in migrations/create-users.js
up: (queryInterface, Sequelize) => {
  return queryInterface.createTable('Users', {
    // other fields...
    organizationId: {
      type: Sequelize.INTEGER,
      allowNull: true,
      onDelete: 'CASCADE',
      references: {
        model: 'Organizations',
        key: 'id',
        as: 'organizationId',
      },
    },
  })
},

Solution 3:[3]

As of "sequelize": "^3.5.1", it only works when you put onDelete='CASCADE' in the belongsTo declaration, which is the Product model in your case. This contradicts the docs: http://sequelize.readthedocs.org/en/latest/api/associations/index.html?highlight=onDelete#hasmanytarget-options

Please see this question:Sequelize onDelete not working

Solution 4:[4]

The problem here is some time migration script generated missing CONSTRAINT for foreign key.

I'm still getting issue event follow official document for { onDelete: 'cascade', hooks: true }.

Here's my solution:

Step 1: Create migration files as usual but no foreign key yet. Remember defined associate as you did

    Product.belongsTo(models.Category);

    Category.hasMany(models.Product);

Step 2: Create migration script to add the foreign key column into table:

'use strict';
module.exports = {
  up: (queryInterface, Sequelize) => {
    return queryInterface.addColumn(
      'Product', // name of Source model
      'categoryId', // name of the key we're adding 
      {
        type: Sequelize.INTEGER,
        references: {
          model: 'Category', // name of Target model
          key: 'id', // key in Target model that we're referencing
        },
        onUpdate: 'CASCADE',
        onDelete: 'CASCADE',
      }
    );
  },
  down: (queryInterface, Sequelize) => {
    return queryInterface.removeColumn(
      'Product', // name of Source model
      'categoryId' // key we want to remove
    );
  }
};

Hope this help!

I found this solution by combine from:

Solution 5:[5]

I finally figured it wasn't working for me because of paranoid. Sequelize doesn't handle cascade, and does a MySQL cascade delete instead. With that said, if you use paranoid with your tables - cascade won't happen since the records are not really deleted from the table.

Solution 6:[6]

On hasMany association add onDelete cascade and set hooks to true like this

 Category.hasMany(models.Product, { onDelete: 'cascade', hooks:true });

Solution 7:[7]

The answer OP had added in the question:

I accomplished this by adding constraint on database using Alter command, as Add Foreign Key Constraint through migration is an open [bug][1] in sequelize.

ALTER TABLE "Products"
ADD CONSTRAINT "Products_CategoryId_fkey" FOREIGN KEY ("CategoryId")
REFERENCES "Categories" (id) MATCH SIMPLE
ON DELETE CASCADE

Solution 8:[8]

I couldn't manage latest "sequelize": "^6.6.5" association cascade to work on existing postgres database with any of mentioned here tips so had to replace it with a model beforeDestroy hook like below

User.beforeDestroy(async user => {
  await Role.destroy({ where: { userId: user.id } })
})

Solution 9:[9]

I don't know why but this {onDelete: 'cascade', hooks: true} didn't work for me. If you are facing that same issue, then try to add a reference related code in your model's migration file.

"use strict";
module.exports = {
    up: async (queryInterface, Sequelize) => {
        await queryInterface.createTable("TravelDetails", {
            id: {
                ......
            },
            event_id: {
                type: Sequelize.INTEGER,
                onDelete: "CASCADE",
                references: {
                    model: "Events",
                    key: "id",
                    as: "eventData",
                },
            },
        });
    },
    down: async (queryInterface, Sequelize) => {
        await queryInterface.dropTable("TravelDetails");
    },
};

Solution 10:[10]

Are you sure you declaring the association between the models?

/models/index.js

const Category  = require('./Category');
const Product = require('./Product');
const ProductTag = require('./ProductTag');
const Tag = require('./Tag');

Category.associate({Product});
Product.associate({Category,Tag});
Tag.associate({Product});

module.exports={Category,Product,ProductTag,Tag};

Model Category.js

'use strict';
const {Model, DataTypes} = require('sequelize');
const sequelize = require('../config/connection.js');

class Category extends Model {
    /**
     * Helper method for defining associations.
     * This method is not a part of Sequelize lifecycle.
     * The `models/index` file will call this method automatically.
     */
    static associate({Product}) {
        // define association here
        console.log('Category associated with: Product');
        this.hasMany(Product, {
            foreignKey: 'category_id',
            onDelete: 'CASCADE'
        });
    }
}

Category.init({
    category_id: {type: DataTypes.INTEGER, autoIncrement: true, allowNull: false, primaryKey: true},
    category_name: {type: DataTypes.STRING, allowNull: false}
}, {
    sequelize,
    timestamps: false,
    freezeTableName: true,
    underscored: true,
    modelName: "Category",
});

module.exports = Category;

Solution 11:[11]

As for sequelize ^6.6.5, because this topic is trending when searching for sequelize CASCADE :

I had to use the onDelete:'cascade' on both the hasMany & belongsTo association to make it work.

 Product.belongsTo(models.Category, { onDelete: 'CASCADE' });
 Category.hasMany(models.Product, { onDelete: 'CASCADE' });

Solution 12:[12]

you need to update only your product migration file. In order when you delete category to be deleted with child products, you need to have in your product migration the following

...
categoryId: {
    type: Sequelize.INTEGER,
    references : {
      model : 'Category',
      key : 'id'
    },
    onUpdate: 'CASCADE',
    onDelete: 'CASCADE',
},
...

no need to add this in model { onDelete: 'cascade' }

Solution 13:[13]

To delete the parent record and also delete the child records.

Add to the child file

onDelete: 'cascade'

and it worked.

ex.

/migrations/profile.js (The foreign key is 'user_id')

'use strict'
module.exports = {
  up: async (queryInterface, Sequelize) => {
    await queryInterface.createTable('profiles', {
      id: {
        allowNull: false,
        primaryKey: true,
        type: Sequelize.UUID,
        defaultValue: Sequelize.UUIDV4,
      },
      name: {
        allowNull: false,
        type: Sequelize.STRING,
      },
      age: {
        allowNull: false,
        type: Sequelize.STRING,
      },
      user_id: {
        allowNull: false,
        type: Sequelize.UUID,
        references: { model: 'users', key: 'id' },
        onDelete: 'CASCADE',????????Add here.??
      },
    })
  },
  down: async (queryInterface, Sequelize) => {
    await queryInterface.dropTable('profiles')
  },
}

Solution 14:[14]

  1. Install sequelize-cli through npm.

  2. After creating a database, make two models, e.g. Category & Products: sequelize model:create --name Category --attributes name:string etc.

  3. Make sure your static method 'associate' inside Category model contains this: "static associate({Product}) {this.hasMany(Product, { foreignKey: 'categoryId', as: 'products', onDelete: 'cascade', hooks: true });"

  4. And for Product modal: "static associate({Category}) {this.belongsTo(Category, { foreignKey: 'categoryId', as: 'category'});

  5. Also make sure your migration file -create-product.js contains this field: categoryId: {type: DataTypes.INTEGER, allowNull: false}

  6. Now run the terminal command: sequelize db:migrate

  7. Write this countoller inside app.js:

    app.delete("/category/:id", async(req, res) => { const id = req.params.id; try { const category = await Category.findOne({ where: { id }, include: 'products' }); await category.destroy(); return res.json({ message: "Category is deleted!"}); } catch (err) { return res.status(500).json({error: "Something went wrong"}); } })

  8. Launch the app with command: "node app.js" and test deleting on cascade in Postman.