LoginSignup
9
2

More than 3 years have passed since last update.

Sequelize でユニークキーを設定する方法 (PostgreSQL)

Posted at

はじめに

Sequelize でユニークキーを設定する方法についてウェブに沢山出てくるものの、
意図したとおりに動作しないものが多数あってハマったため、
上手くいった方法を残しておきます。(2019/6/13)

ユニークキーを設定する

該当フィールドに unique: true と記述すれば可能です。
よくあるユーザ登録時に重複したメールアドレス登録させないとかで設定する場合は、
下記のようなコードになります。

20190416081113-create-user.js
module.exports = {
  up: (queryInterface, Sequelize) => queryInterface.sequelize.query('CREATE EXTENSION IF NOT EXISTS "uuid-ossp";')
    .then(() => queryInterface.createTable('users', {
      id: {
        allowNull: false,
        primaryKey: true,
        defaultValue: Sequelize.literal('uuid_generate_v4()'),
        type: Sequelize.UUID,
      },
      name: {
        allowNull: false,
        type: Sequelize.STRING
      },
      email: {
        allowNull: false,
        type: Sequelize.STRING,
        unique: true, // unique パラメータに true を設定すれば OK
      },
      password: {
        allowNull: false,
        type: Sequelize.STRING,
      },
      created_at: {
        allowNull: false,
        type: Sequelize.DATE,
        defaultValue: Sequelize.literal('CURRENT_TIMESTAMP'),
      },
      updated_at: {
        allowNull: false,
        type: Sequelize.DATE,
        defaultValue: Sequelize.literal('CURRENT_TIMESTAMP'),
        onUpdate : Sequelize.literal('CURRENT_TIMESTAMP'),
      }
    })),
  down: (queryInterface, Sequelize) => {
    return queryInterface.dropTable('users');
  }
};

sequelize db:migrate を実行した後に、
実際に SQL を叩いて index が作成されていることを確認します。

test_unique=#SELECT tablename, indexname FROM pg_indexes WHERE indexname='users_email_key';
 tablename |    indexname    
-----------+-----------------
 users     | users_email_key
(1 row)

test_unique=# \d users_email_key
           Index "public.users_email_key"
 Column |          Type          | Key? | Definition 
--------+------------------------+------+------------
 email  | character varying(255) | yes  | email
unique, btree, for table "public.users"

複合ユニークキーを設定する

マイグレーションファイルに出力される queryInterface.createTable の第3引数には option を指定することが出来、そこに uniqueKeys の項目を追加することで複合ユニークキーを記述することが可能です。
中間テーブルで重複した ID の組み合わせを排除するパターンでの使用は下記になります。

20190507060929-create-users-workspaces.js
'use strict';
module.exports = {
  up: (queryInterface, Sequelize) => {
    return queryInterface.createTable('users_workspaces', {
      id: {
        allowNull: false,
        autoIncrement: true,
        primaryKey: true,
        type: Sequelize.INTEGER
      },
      user_id: {
        allowNull: false,
        type: Sequelize.UUID,
      },
      workspace_id: {
        allowNull: false,
        type: Sequelize.UUID,
      },
      created_at: {
        allowNull: false,
        type: Sequelize.DATE,
        defaultValue: Sequelize.literal('CURRENT_TIMESTAMP'),
      },
      updated_at: {
        allowNull: false,
        type: Sequelize.DATE,
        defaultValue: Sequelize.literal('CURRENT_TIMESTAMP'),
        onUpdate : Sequelize.literal('CURRENT_TIMESTAMP'),
      }
    }, {
      // ここで複合ユニークキーの情報を記載する
      // fields の部分に複合ユニークキーとして設定したいフィールドを含める
      // 2つ以上設定することも可
      uniqueKeys: {
          UsersWorkspacesIndex: {
              fields: ['user_id', 'workspace_id']
          }
      }
    });
  },
  down: (queryInterface, Sequelize) => {
    return queryInterface.dropTable('users_workspaces');
  }
};

sequelize db:migrate を実行した後に、
実際に SQL を叩いて index が作成されていることを確認します。

test_unique=# SELECT tablename, indexname FROM pg_indexes WHERE indexname='users_workspaces_user_id_workspace_id_key';
    tablename     |                 indexname                 
------------------+-------------------------------------------
 users_workspaces | users_workspaces_user_id_workspace_id_key
(1 row)

test_unique=# \d users_workspaces_user_id_workspace_id_key
Index "public.users_workspaces_user_id_workspace_id_key"
    Column    | Type | Key? |  Definition  
--------------+------+------+--------------
 user_id      | uuid | yes  | user_id
 workspace_id | uuid | yes  | workspace_id
unique, btree, for table "public.users_workspaces"

おわりに

Sequelize のみならず CLI でデータベースのマイグレーション作業を行う場合は、
意図通りのインデックスが貼られるかテストしながら作業進めたほうがいいなと感じました。

参考リンク

https://github.com/sequelize/sequelize/pull/9946/files
https://github.com/sequelize/sequelize/issues/9041

9
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
2