loading...

add new non-null, unique column using Sequelize migration

rohit_ambre profile image Rohit Ambre Updated on ・2 min read

This short article is to explain how you can add a new non-null and unique column in an existing Relational database using sequelize migration in nodeJS.

Note: This is for development environments and not recommended for production.

Sometimes while writing any application we might require to add new non-null and unique column in the existing database without dropping the current table, so I tried doing it in my demo project where I'm using sequelize ORM, and I'm writing this article because I couldn't find the complete solution at one place, so here's my attempt at solving this.

Problem description

Consider we have users table with the following columns and now we want to add a new username column which has to be unique and non-null to this without dropping the table.

| id | name  | email                 | age | hobby   |
|----|-------|-----------------------|-----|---------|
| 1  | bob   | bob@mars.com          | 23  | coding  |
| 2  | alice | alice01@jupyter.com   | 25  | dance   |
| 3  | John  | superjohn@earth.com   | 22  | singing |
| 4  | frank | frank@saturn.com      | 28  | reading |

Solution

One simple solution is to insert the same email field in username column as both are unique but we'll take general example where this is not possible.

Let's start by creating a migration file using sequelize-cli

npx sequelize migration:create --name=add_username_users

Here's a screen capture of pseudo code
migration pseudo code

To explain, First we add username column with just unique constraint on its success we write any logic to update every row of newly added username column with any logic you like. I used { type: QueryTypes.SELECT } in SELECT query as we don't need metadata here and to get query results in an array on its success will alter the column to add not-null constraint. For the down part of sequelize migration will just drop the username column.

Here's my final code to add a new column with a randomly generated username, which can be updated later or can be kept as it is during the development environment.

const { QueryTypes } = require('sequelize');
module.exports = {
  up: (queryInterface, Sequelize) => {
    return queryInterface.addColumn('users','username',{
      type: Sequelize.STRING,
      unique: true
    }).then((data) => {
      queryInterface.sequelize
        .query(`SELECT id from users`, {
          type: QueryTypes.SELECT
        })
        .then((rows) => {
          rows.map((row) => {
            queryInterface.sequelize.query(
              `UPDATE users SET username='${Math.random()
                .toString(36).substr(2, 8)}' WHERE id=${row.id};`
            );
          });
          Promise.resolve();
        })
        .then(() => {
          queryInterface.changeColumn('users', 'username', {
            type: Sequelize.STRING,
            allowNull: false
          });
        });
    })
  },
  down: async (queryInterface, Sequelize) => {
    await queryInterface.removeColumn('users', 'username');
  }
};

Thank you for reading and please share your thoughts on it.

References:
random generation: stackOverflow answer
code idea: sequelize github issue

Posted on by:

rohit_ambre profile

Rohit Ambre

@rohit_ambre

Working as a Software developer. Always looking out for contributions on open source project.

Discussion

pic
Editor guide
 

Great stuff man