Sequelize を使って Express サーバから MySQL DB を操作してみる
Express サーバから MySQL DB とのやり取りを行おうと思い、Node.js で使える良い O/R マッパーがないか調べてみたところ、Sequelize というモノがよく使われているようだったので試してみた。
- Sequelize | Sequelize ORM
- GitHub - sequelize/sequelize: An easy-to-use multi SQL dialect ORM for Node.js
インストール
以下の公式ドキュメントに沿って、まずは Sequelize をインストールする。
Sequelize と同時に、利用する DB に合わせたパッケージもインストールする必要がある。今回は MySQL を使用するので mysql2
というパッケージを入れることになる。
$ npm install -S sequelize mysql2
単体で使ってみる
まずは Express サーバに組み込まず、単独の Node.js スクリプトとして使ってみる。
const Sequelize = require('sequelize');
// 接続先情報
const host = 'my-sql-server.com';
const database = 'my_db';
const username = '【ユーザ名】';
const password = '【パスワード】';
// 接続開始
const sequelize = new Sequelize(database, username, password, {
host: host,
dialect: 'mysql',
operatorsAliases: false,
pool: {
min: 0,
max: 5,
acuire: 30000,
idle : 10000
}
});
// 接続確認用
sequelize.authenticate()
.then(() => { console.log('Success test connection'); })
.catch((error) => { console.log('Failure test connection', error); });
// users テーブルに対応するモデルを作成する
const UserModel = sequelize.define('users', { // CREATE TABLE 文で指定した内容は大体以下のような感じ
id : { field: 'id' , type: Sequelize.INTEGER(11) , primaryKey: true, autoIncrement: true }, // INT(11) NOT NULL PRIMARY KEY AUTO_INCREMENT
userName : { field: 'user_name' , type: Sequelize.STRING(100) , allowNull: false }, // VARCHAR(100) NOT NULL
address : { field: 'address' , type: Sequelize.STRING(500) }, // VARCHAR(500) DEFAULT NULL
createdAt: { field: 'created_at', type: Sequelize.DATE }, // DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
updatedAt: { field: 'updated_at', type: Sequelize.DATE } // DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
});
// 全件取得してみる
UserModel.findAll()
.then((result) => {
console.log('データ取得', result.dataValues);
});
こんなスクリプト sequelize-test.js
を作成し、$ node sequelize-test.js
で実行してみよう。SELECT * FROM users;
相当の SQL が実行され、データが取得できれば OK だ。
DB 接続に関するところは特段説明も要らないだろう。接続先情報を書いて渡してやれば良い。プールの設定などもできるので、この辺を調整したい場合は公式のドキュメントを読む。
モデルの定義
DB テーブルに対応するモデルを作成するのが、sequelize.define()
部分。ココで、DB 上はスネークケースで作成しているフィールド名を、キャメルケースのプロパティ名に直している。
const UserModel = sequelize.define('【DB テーブル名】', {
// +--- モデルのプロパティ +--- フィールド定義 : 型を示す専用のメソッドを使う
// | +--- DB カラム名 | +--- primaryKey 指定などがあれば行える
// | | | |
id : { field: 'id' , type: Sequelize.INTEGER(11) , primaryKey: true, autoIncrement: true },
userName : { field: 'user_name' , type: Sequelize.STRING(100) , allowNull: false },
address : { field: 'address' , type: Sequelize.STRING(500) },
createdAt: { field: 'created_at', type: Sequelize.DATE },
updatedAt: { field: 'updated_at', type: Sequelize.DATE }
});
DB 側と同じケースで命名していれば、このような変換は要らず、userName: { type: Sequelize.STRING }
のように短く書いたりも出来る。詳しくは API リファレンスを参照しよう。
CRUD 操作してみる
上の例では Model#findAll()
というメソッドを使って、users
テーブルの全データを取得した。このように、Promise でデータが送り返されてくる作りだ。
以下に UserModel
の場合の基本的な CRUD 操作のコードを書いておく。
// SELECT : 条件を指定して複数件取得する
UserModel.findAll({
where: {
address: '東京'
}
})
.then((result) => {
// 結果の配列データは result.dataValues が持っている
});
// SELECT : ID (キー) を指定して1件取得する
UserModel.findById(id)
.then((result) => {
// 結果のオブジェクトは result.dataValues が持っている
});
// INSERT : 新規追加
// id は自動採番させるため指定しない (指定するとその内容で INSERT される)
// created_at・updated_at も DB 側に自動更新させるため未指定
UserModel.create({
userName: '山田 太郎',
address : '北海道'
})
.then((result) => {
// 新規追加できた結果オブジェクトは result.dataValues が返してくれる
});
// UPDATE : 更新
UserModel.update({
// 更新したい Key・Value を指定する
userName: '田中 邦衛',
address : '沖縄'
}, {
// 更新対象を指定する
where: {
id: 29
},
// 更新するフィールド名を指定する
fields: [
'userName',
'address'
]
})
.then(() => { });
// DELETE : 削除
UserModel.destroy({
// 削除対象を指定する
where: {
id: 42
}
})
.then(() => { });
他にも findOrCreate
や upsert
など、便利なメソッドが多数用意されている。
- 参考 : Manual | Sequelize
Express サーバに組み込んでみる
ココまでで Sequelize を使った CRUD 操作はできるようになったと思うので、Express サーバに組み込んでみる。
といっても、コントローラでやることとしては、リクエストデータからパラメータを拾い上げて、それを元に Model.findAll()
なり Model.update()
なりの引数にセットしていくだけだ。結果を受け取ったらそれをレスポンスにセットすれば良いだけ。
モデルをどう用意するか、についてだが、以下のような共通クラスを用意するのが良いと思う。
/* app/models/models.js */
const Sequelize = require('sequelize');
// 接続情報 (省略)
// 接続開始 (省略)
const sequelize = new Sequelize(database, username, password, {
host: host,
dialect: 'mysql',
operatorsAliases: false
});
// モデルを定義する
const Models = {};
// 各モデルを設定する
Models.User = require('./user-model')(sequelize);
Models.Product = require('./product-model')(sequelize); // user-model.js 的なファイルがあるテイ
// Sequelize 本体を設定する
Models.sequelize = sequelize;
Models.Sequelize = Sequelize;
// エクスポートする
module.exports = Models;
/* app/models/user-model.js */
// 型定義用に require しておく
const Sequelize = require('sequelize');
module.exports = (sequelize) => {
const UserModel = sequelize.define('users', { // CREATE TABLE 文で指定した内容は大体以下のような感じ
id : { field: 'id' , type: Sequelize.INTEGER(11) , primaryKey: true, autoIncrement: true }, // INT(11) NOT NULL PRIMARY KEY AUTO_INCREMENT
userName : { field: 'user_name' , type: Sequelize.STRING(100) , allowNull: false }, // VARCHAR(100) NOT NULL
address : { field: 'address' , type: Sequelize.STRING(500) }, // VARCHAR(500) DEFAULT NULL
createdAt: { field: 'created_at', type: Sequelize.DATE }, // DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
updatedAt: { field: 'updated_at', type: Sequelize.DATE } // DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
});
return UserModel;
};
このようなモデル生成用のファイル models.js
をベースに、テーブルごとに user-model.js
・product-model.js
とファイルを分けておくと管理しやすいかと。
で、コントローラでは models.js
を require()
して使う。ルーティング部分は省略するが、リクエストとレスポンスを引数で受け取っているテイ。
/* app/controllers/users-controller.js */
// Models を読み込む
const Models = require('../models/models');
class UsersController {
/** 検索するアクション */
findAll(req, res) {
// オプションの雛形を作っておく
const options = {
where: {}
};
// リクエストで address パラメータを指定されていれば、絞り込み検索のためのオプションとして追加する
if(req.query['address']) {
options.where['address'] = req.query['address'];
}
// User モデルを使用する
Models.User.findAll(options)
.then((result) => {
// 200:OK と、JSON 形式の結果データ dataValues を返す
res.status(200);
res.json(result.dataValues);
})
.catch((error) => {
// 404:NotFound と、エラー情報を返す
res.status(404);
res.json(error);
});
}
}
こんな風に Express サーバを作っておけば、http://localhost/users
で全件、http://localhost/users?address=Tokyo
で絞り込み検索した結果が受け取れる、API サーバの出来上がり。
SELECT の際の条件指定や、INSERT・UPDATE の際のモデル構築処理などは、コントローラから外出しして管理していくと良いだろう。
以上。DB 操作がかなり簡単になったので、Sequelize オススメ!