プログラム関係の備忘録。技術系記事1000記事以上を目指すブログ

sequelizeの導入方法と使い方(Express)

  • 2020年7月11日
  • 2020年7月23日
  • node.js
  • 2925view
  • 0件

Expressで作ったアプリを、sequelizeを使ったプロジェクト構成に作り直したときのメモ。

sequelize: 6.3.1
mysql2: 2.1.0

パッケージのインストール

npm install -g sequelize-cli
npm i -s sequelize

プロジェクト構成と設定ファイルの準備

express-generatorがベース

各プロジェクト配下に以下ディレクトリを作成

models\
migrations\
config\
seeders\

以下のコマンドで一括生成できる。

sequelize-cli init

config内にconfig.jsonを作成

アプリの設定値を持たせておくファイルだが、sequelizeを使うにあたり「”DIALECT”:”mysql”」という値を持たせておく。(mySQLの場合)

{
    "development": {
        "host": "localhost",
        "username": "root",
        "password": "***",
        "database": "***",
        "dialect": "mysql"
    },
    "staging": {
        "host": "localhost",
        "username": "***",
        "password": "***",
        "database": "***",
        "dialect": "mysql"
    },
    "production" : {
        "host": "localhost",
        "username": "***",
        "password": "***",
        "database": "***",
        "dialect": "mysql"
    }
}

model内にindex.jsを作成

"use strict";

var fs = require("fs");
var path = require("path");
var Sequelize = require("sequelize");
var basename = path.basename(__filename);
var env = process.env.NODE_ENV || "development";
var config = require(__dirname + "/../config/config.json")[env];
var db = {};

/**
 * sequelizeの設定
 */
let sequelize = new Sequelize(
    config.database,
    config.username,
    config.password,
    config
)

fs.readdirSync(__dirname)
  .filter(file => {
    return (
      file.indexOf(".") !== 0 && file !== basename && file.slice(-3) === ".js"
    );
  })
  .forEach(file => {
    const model = require(path.join(__dirname, file))(sequelize, Sequelize.DataTypes);
    db[model.name] = model;
  });

Object.keys(db).forEach(modelName => {
  if (db[modelName].associate) {
    db[modelName].associate(db);
  }
});

db.sequelize = sequelize;
db.Sequelize = Sequelize;

module.exports = db;

modelsを作成

sequelize-cliをグローバルインストールしてあるため、ターミナルでのmodel作成ができます。(もちろん手動でも)

sequelize model:generate --name テーブル名 --attributes name:string,age:integer

上記のようにコマンドを叩くと(値はそれぞれ書き換えてください)で、migrationsとmodelsが生成される。

sequelizeは、idCreatedAtUpdatedAtの3フィールドを自動的に作成してくれるので、それ以外の値を入れればよいそうです。

sequelizeでmigrateをおこなう

migrateの実行

定義したテーブルをDBに作成するには以下のmigrateコマンドを叩きます。

sequelize-cli db:migrate

テーブルが作成されることが確認できます。
初回はマイグレーション管理用に「sequelizemeta」というテーブルも作られます。

実行したmigrateひとつ前の状態に戻す

sequelize-cli db:migrate:undo

migrateを全て元に戻す

sequelize-cli db:migrate:undo:all

Seedを使う

テストデータや初期データなどを予め定義しておくことができる。

sequelize-cli seed:generate --name 任意のテーブル名

seeders配下に以下のファイルが生成される

'use strict';

module.exports = {
  up: async (queryInterface, Sequelize) => {
    /**
     * Add seed commands here.
     *
     * Example:
     * await queryInterface.bulkInsert('People', [{
     *   name: 'John Doe',
     *   isBetaMember: false
     * }], {});
    */
  },

  down: async (queryInterface, Sequelize) => {
    /**
     * Add commands to revert seed here.
     *
     * Example:
     * await queryInterface.bulkDelete('People', null, {});
     */
  }
};

こんな感じでジャンジャン追加しておく(例)

    const now = new Date();
    await queryInterface.bulkInsert('m_users', [
      { login_id: 'test@test.com', password: '1111', zipcode: '001-0001', lastname: '田中', firstname: '幸子', icon_img: '', tel: '', address1:'', address2:'', address3:'', createdAt: now, updatedAt: now, can_receive: 1, del_flg:0 }
      ,{ login_id: 'test2@test.com', password: '1111', zipcode: '001-0001', lastname: '山田', firstname: '誠', icon_img: '', tel: '', address1:'', address2:'', address3:'', createdAt: now, updatedAt: now, can_receive: 1, del_flg:0 }
      ,{ login_id: 'test3@test.com', password: '1111', zipcode: '001-0001', lastname: '河合', firstname: '智司', icon_img: '', tel: '', address1:'', address2:'', address3:'', createdAt: now, updatedAt: now, can_receive: 1, del_flg:0 }
      ,{ login_id: 'test4@test.com', password: '1111', zipcode: '001-0001', lastname: '斎藤', firstname: '省吾', icon_img: '', tel: '', address1:'', address2:'', address3:'', createdAt: now, updatedAt: now, can_receive: 1, del_flg:0 }
      ,{ login_id: 'test5@test.com', password: '1111', zipcode: '001-0001', lastname: '本田', firstname: '由美', icon_img: '', tel: '', address1:'', address2:'', address3:'', createdAt: now, updatedAt: now, can_receive: 1, del_flg:0 }
    ], {});
  },

seedの実行

sequelize-cli db:seed:all

データを元に戻す

sequelize-cli db:seed:undo:all

データ取得

ようやくという感じですが。
任意のルーティングの配下で以下のように記述

…省略
var db = require('../../../models/index.js');

router.get('/', (req, res) => {
  db.User.findAll()
  .then((result) => {
    res.send(result)
  })
  .catch((error) => {
    logger.error(error)
    res.status(error.status).json(error)
  })
})

Curlコマンドなどで叩いてseedで入れたデータが取得できればひとまずOK

トラブルシューティング

工程を進めていく中で発生したエラーなど。

ERROR: Dialect needs to be explicitly supplied as of v4.0.0

マイグレーション時のエラー。コンフィグファイルのjson構成にオリジナリティを採用してしまっていたため。

ERROR: Please install mysql2 package manually

mysql2のパッケージを使ってくれとのこと。

sequelize.import is not defined

めちゃめちゃハマりました。
sequelizeなかなかアップデートが多いようで、参考にした記事はどれも、model配下のindex.jsの一部で以下のように記載しています。

var model = sequelize["import"](path.join(__dirname, file));

しかし、sequelize initをすると生成されるindex.jsはこうなってます。

const model = require(path.join(__dirname, file))(sequelize, Sequelize.DataTypes);

わかってしまえばなんてことなさすぎる事象ですが、これに気づくのに5時間。
ネットの記事を参考にindex.jsを手動で作ったのですが、おとなしくsequelize initをしていればこうはなってなかった・・。

感想

ORMって便利だけど、学習コストかかりますよね。
https://blog.capilano-fw.com/?p=5582
↑こちらの方のモデルの使い方を読みましたが、正直SQL書いたほうが早いでしょって思っちゃいましたが、その考えをしてしまうと古いものに固執するイタいエンジニアになってしまうなと。ただMyBatisやLaravelのEloquentとかのほうが全然わかりやすいわ。

まとめ

最後に繰り返しよく使いそうなコマンドのみ箇条書きにまとめておきます。

modelsの作成

sequelize model:generate --name テーブル名 --attributes name:string,age:integer,...

migrateの実行

sequelize-cli db:migrate

実行したmigrateひとつ前の状態に戻す

sequelize-cli db:migrate:undo

migrateを全て元に戻す

sequelize-cli db:migrate:undo:all

Seedの作成

sequelize-cli seed:generate --name 任意のテーブル名

seedの実行

sequelize-cli db:seed:all

seedのデータを元に戻す

sequelize-cli db:seed:undo:all