Node.jsでSequelizeを使ってRDBを扱う
日付 タグ node.js カテゴリ node.js目次
Node.jsからSequelizeでSQLite3を扱う
Node.jsからRDB(MySQL, PostgreSQL, MariaDBやSQLiteなど)を扱う場合、各々に対応したパッケージを利用してもいいのだが、何かしらのORM(Object Relational Mapping)を利用しておけば、どのDBシステムを利用するにしても同じようにプログラム実装できて、DBシステムのスイッチもしやすい。
そこで、Node.jsで良く使われているORMであるSequelizeを利用して、今回はSQLite3のDBにデータを書き込む手順を見ていく。
https://sequelize.org/ - Sequelize ORM
なお、今回作ったサンプルのソースコードは参照用としてGithubの以下に置いてある。 https://github.com/hugodeblog/node-sequelize
sequelizeのインストールとサンプルコード
今回もまずはサンプルディレクトリの作成とパッケージインストールから
$ mkdir node-sequelize
$ cd node-sequelize
$ npm init --yes
$ npm install --save sequelize
$ npm install --save sqlite3
$ npm install --save js-yaml
sequelizeだけでなく、DBとしてsqlite3を使うので、sqlite3のパッケージもインストール。
また、DB接続の設定をyamlに書いて、それをプログラムから読み込むので、js-yamlもインストールしている。
簡単なサンプルとして、sequelizeを利用するsequelize.mjs を作成した。
sequelize.mjs
import Sequelize from 'sequelize';
import { default as jsyaml } from 'js-yaml';
import * as util from 'util';
import { promises as fs } from 'fs';
class User extends Sequelize.Model {}
let sequlz;
async function connectDB() {
if(sequlz) return sequlz;
const yamltext = await fs.readFile('sequelize-sqlite.yaml', 'utf8');
const params = await jsyaml.safeLoad(yamltext, 'utf8');
sequlz = new Sequelize(
params.dbname,
params.uesrname,
params.password,
params.params
);
User.init({
username: {type: Sequelize.STRING, unique: true},
password: Sequelize.STRING,
address: Sequelize.STRING
}, {
sequelize: sequlz,
modelName: 'User',
timestamps: true
});
await User.sync({ force: true });
}
async function closeDB() {
if (sequlz) sequlz.close();
sequlz = undefined;
}
async function create(user, pass, address) {
await connectDB();
const result = await User.create( {
username:user, password:pass, address:address
});
}
async function update(user, pass, address) {
await connectDB();
var result = await User.findOne( {where:{username:user} });
if(!result) {
throw new Error(`Not found for ${user}`);
} else {
await User.update(
{password:pass, address:address},
{where:{username:user}}
);
result = await User.findOne( {where:{username:user} });
}
}
async function destroy(user) {
await connectDB();
var result = await User.findOne( {where:{username:user} });
if(!result) {
throw new Error(`Not found for ${user}`);
} else {
await User.destroy( {where: {username: user} });
}
}
async function readall() {
await connectDB();
const results = await User.findAll({});
console.log('currentDB status:');
console.log(results.map(result => (
{'username': result.username, 'password':result.password, 'address':result.address}
)));
}
(async () => {
console.log('******** Sequelizeテストスタート ********');
try {
await connectDB();
console.log('******** データ作成 ********');
await create('taro', 'taro123', 'Tokyo');
await create('jiro', 'jiro456', 'Osaka');
await create('sabro', 'jiro789', 'Hokkaido');
await readall();
console.log('******** jiroのデータアップート ********');
await update('jiro', '456jiro', 'Kanagawa');
await readall();
console.log('******** taroのデータ削除 ********');
await destroy('taro');
await readall();
} catch (err) {
console.error(err);
console.log('エラーが出たのでテストを終了します');
} finally {
console.log('******** Sequelizeテスト終了 ********');
closeDB();
}
})();
DBへの接続とテーブル作成
少しプログラムの作りを見ておこう。
const yamltext = await fs.readFile('sequelize-sqlite.yaml', 'utf8'); const params = await jsyaml.safeLoad(yamltext, 'utf8');
まずはsequelize-sqlite.yaml にてDBへの接続情報を指定。そのパラメーターを読み込んでいる。
SQLite3の場合、ユーザー名、パスワードなしでローカルPCにおいてあるDBファイルへのアクセスだが、MySQL等を利用する場合は、DBアクセス時にDBのユーザー名、パスワードが必要になる。
dbname: users
username:
password:
params:
dialect: sqlite
storage: users-sequelize.sqlite3
logging: false
なお、sequelizeではデフォルトだと、SQL命令発行のログがかなり多くなるので、ログ出力を抑えたければ、logging:false を指定しておく方がいいだろう。
ここでDB接続のパラメーターをyamlファイルから読み込まれば、Sequelizeのインスタンスを作成してDB接続ができる。
sequlz = new Sequelize( params.dbname, params.uesrname, params.password, params.params );
次にDB上で今回テストに使うテーブルを作成する。
User.init({ username: {type: Sequelize.STRING, unique: true}, password: Sequelize.STRING, address: Sequelize.STRING }, { sequelize: sequlz, modelName: 'User', timestamps: true }); await User.sync({ force: true });
今回テーブル名はUsers(Userの複数形)になり、Sequelizeが自動的にデータに対して付加してくれるカラムcreatedAt, updatedAtも利用する。 timestamps: true はデフォルトでtrueなのであえて書かなくても、デフォルトで勝手に付与してくれるidの他にcreatedAt, updatedAtを利用することができる。createdAt, updatedAtが不必要ならtimestamps: false とすれば良い。 なお、SQLite3ではタイムゾーンの概念がなくUTC時刻で記録されることには注意が必要。
User.sync({ force: true }); によって毎回テストする時にテーブルをDropして作り直している。
- User.sync()
- テーブルが存在しなければテーブル作成する
- User.sync({ force: true })
- もしもテーブルがすでに存在していればテーブルをDropして作りなおす
- User.sync({ alter: true })
- テーブルが存在していて、テーブルのカラムとかに変更あるようならAlterテーブルする
データのINSERT
さて新規でデータを追加するにはどうするのか。
async function create(user, pass, address) { await connectDB(); const result = await User.create( { username:user, password:pass, address:address }); }
usernameカラムにuser、passwordカラムにpass、addressカラムにaddressのデータがINSERTされる。
データのUPDATE
async function update(user, pass, address) { await connectDB(); var result = await User.findOne( {where:{username:user} }); if(!result) { throw new Error(`Not found for ${user}`); } else { await User.update( {password:pass, address:address}, {where:{username:user}} ); result = await User.findOne( {where:{username:user} }); } }
データのアップデートではまずアップデートする対象のユーザーデータが存在するかどうかチェックしている。もしなければエラーをthrowする。 データが存在すればupdateによって各カラムを更新している。
データのDELETE
async function destroy(user) { await connectDB(); var result = await User.findOne( {where:{username:user} }); if(!result) { throw new Error(`Not found for ${user}`); } else { await User.destroy( {where: {username: user} }); } }
データの削除でもまずアップデートする対象のユーザーデータが存在するかどうかチェックしている。もしなければエラーをthrowする。 データが存在すればdestoryによってユーザー名をキーにしてデータを検索して削除している。
全データの読み込み
生成(INSERT)、編集(UPDATE)、削除(DELETE)については見てきたが、デバッグ用にDBテーブル中の全データをダンプ表示する機能も欲しいので、それも実装として付け足す。
async function readall() { await connectDB(); const results = await User.findAll({}); console.log('currentDB status:'); console.log(results.map(result => ( {'username': result.username, 'password':result.password, 'address':result.address} ))); }
findAllで取り出した情報からusername、password、addressに関する部分だけ取り出してコンソールログ表示。
サンプルコードの実行確認
さて、今しがたのサンプルを実行してみよう。
$ node sequelize.mjs
******** Sequelizeテストスタート ********
******** データ作成 ********
currentDB status:
[
{ username: 'taro', password: 'taro123', address: 'Tokyo' },
{ username: 'jiro', password: 'jiro456', address: 'Osaka' },
{ username: 'sabro', password: 'jiro789', address: 'Hokkaido' }
]
******** jiroのデータアップート ********
currentDB status:
[
{ username: 'taro', password: 'taro123', address: 'Tokyo' },
{ username: 'jiro', password: '456jiro', address: 'Kanagawa' },
{ username: 'sabro', password: 'jiro789', address: 'Hokkaido' }
]
******** taroのデータ削除 ********
currentDB status:
[
{ username: 'jiro', password: '456jiro', address: 'Kanagawa' },
{ username: 'sabro', password: 'jiro789', address: 'Hokkaido' }
]
******** Sequelizeテスト終了 ********
問題なく実行できて、データの作成、編集、削除ができることが確認できた。
なお、SQLite3を扱う時は、DB Browser for SQLiteを入れておくとデータの確認など何かと便利であるのインストールしておくといいだろう。
https://sqlitebrowser.org/ - DB Browser for SQLite
ここから自分の場合だとMac版をダウンロードしてインストールすれば良い。
DB Browser for SQLiteをインストールしてあれば、GUI上で最終的なDBのデータをこんな感じでデータ閲覧が可能になる。