How to work around Sequelize’s unique constraints in belongsToMany associations

Ari Kramer
2 min readMar 10, 2018

For so many things, Sequelize is fantastic. The Node-based ORM allows JavaScript programmers to easily construct models, create instances on those models, query for specific instances and — why we’re here — set up associations between models.

Associations can help us developers in many ways, but sometimes they can cause us pain. Let’s set up two example models before we dive into specifics.

const Sequelize = require('sequelize');
const db = require('../db'); //this is assuming you already have created a database elsewhere
const User = db.define('user', {
name: Sequelize.STRING,
password: Sequelize.STRING
})
const Product = db.define('product', {
name: Sequelize.STRING,
price: Sequelize.INTEGER
})

Say we have an online store. We have users who can log in and purchase products. If we want to store order history, a many-to-many association could help us. Sequelize has a built-in many-to-many association that we could set up like so:

Product.belongsToMany(User, {through: 'UserProducts'})
User.belongsToMany(Product, {through: 'UserProducts'})

This association not only creates a join table for us. It also adds some useful class methods onto our models, such as User.getProducts()

However, we might run into a serious problem here. Say user1 loved product14 so much that he wanted to purchase it a second time. The belongsToMany association has a unique constraint that would not allow that second purchase to be stored in our UserProducts table. Sequelize would recognize the UserProducts table already has an entry with userId: 1 and productId: 14 and it would throw a long, nasty error.

Surely Sequelize must allow us to manually enable duplicate entries, right?

The good news is there is always a work-around.

The first step: delete your associations. Yes, DELETE YOUR ASSOCIATIONS. You can always add the class methods onto the model you’re about to create for yourself.

The second step: manually create your UserProduct model.

const Sequelize = require('sequelize');
const db = require('../db');
const UserProduct = db.define('userProduct', {
id: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true,
},
userId: Sequelize.INTEGER,
productId: Sequelize.INTEGER
})

Now, just use UserProduct.create({userId: 1, productId: 14}) as many times as you want, and you’ll create as many entries as you want.

Again, the only things we’ve really sacrificed here are 1) the methods that come with a belongsToMany association and 2) the few seconds it took to build our own UserProduct table.

--

--