Cli: Unable to create composite unique constraint

Created on 10 Mar 2016  路  9Comments  路  Source: sequelize/cli

If my model contains a composite unique constraint defined this way:

        system_id: {
            type: DataTypes.STRING,
            unique: 'action'
        },
        rule_id: {
            type: DataTypes.STRING,
            unique: 'action'
        },
        plan_id: {
            type: DataTypes.INTEGER,
            unique: 'action'
        }

then Sequelize adds the composite unique constraint properly. (UNIQUE action (system_id, rule_id, plan_id)).

If however I try to use the same construct in a migration file:

            system_id: {
                type: Sequelize.STRING,
                unique: 'action'
            },
            rule_id: {
                type: Sequelize.STRING,
                unique: 'action'
            },
            plan_id: {
                type: Sequelize.INTEGER,
                unique: 'action',
            }

no unique constraint is generated for the table.

Is this supposed to work or am I doing something wrong? I am using MariaDB.

question

Most helpful comment

After digging through the code I found a way to add a composite unique constraint in a migration without adding an index:

queryInterface.createTable('actions', {
            id: {
                type: Sequelize.INTEGER,
                primaryKey: true,
                autoIncrement: true
            },
            system_id: {
                type: Sequelize.STRING,
            },
            rule_id: {
                type: Sequelize.STRING,
            },
            plan_id: {
                type: Sequelize.INTEGER,
                unique: 'actions_unique',
            }
        }, {
            uniqueKeys: {
                actions_unique: {
                    fields: ['system_id', 'rule_id', 'plan_id']
                }
            }
        });

All 9 comments

One way to achieve what I need seems to be to add a unique index.

After digging through the code I found a way to add a composite unique constraint in a migration without adding an index:

queryInterface.createTable('actions', {
            id: {
                type: Sequelize.INTEGER,
                primaryKey: true,
                autoIncrement: true
            },
            system_id: {
                type: Sequelize.STRING,
            },
            rule_id: {
                type: Sequelize.STRING,
            },
            plan_id: {
                type: Sequelize.INTEGER,
                unique: 'actions_unique',
            }
        }, {
            uniqueKeys: {
                actions_unique: {
                    fields: ['system_id', 'rule_id', 'plan_id']
                }
            }
        });

I am going to send a PR later and move some of the logic from model.js to query-interface.js so that the same approach to defining composite unique constraints can be used in both model and migrations.

I do something similar:

            uniqueKeys : [{
                name        : "Unique value per currency",
                singleField : false,
                fields      : ["cuv_currency", "cuv_value"],
            }],

The changes you are proposing are for sequelize itself and not the cli. If you have no more questions, please close this issue.

@Americas - Do you use that same code in migration and in the model definition under options?

No, in the model we have to use the unique property on each attribute.

Define 'unique: true' attribute to each key

`key1: {
// needs to be unique
type: DataTypes.STRING,
allowNull: false,
unique: true
},

key2: {
// needs to be unique
type: DataTypes.STRING,
allowNull: false,
unique: true
}`

I'm using Sequelize 4.38.0 and couldn't get any of the previous presented solutions working. Creating a new migration to add the unique constraint (instead of doing it along with the table creation) solved the problem:

module.exports = {
    up: (queryInterface, Sequelize) =>
        queryInterface.addConstraint('TableName', ['field1', 'field2'], {
            type: 'unique',
            name: 'indexname'
        }),
    down: queryInterface => queryInterface.removeConstraint('TableName', 'indexname')
};

@notsag-dev Thanks for the decision. It is strange why this is not in the documentation.
Can you explain one thing, when I add it to the migration file, can I somehow add this condition to the model file? Or do I need to manually change the model file? Or is there a way to create a model file from a migration file automatically?

{
    field1: {
        type: DataTypes.STRING,
        unique: 'indexname'
    },
    field2: {
        type: DataTypes.STRING,
        unique: 'indexname'
    },
}
Was this page helpful?
0 / 5 - 0 ratings