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
は、id
、CreatedAt
、UpdatedAt
の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