3. データベース接続
Expressはデータベースに接続してデータを読み書きするような機能は提供していませんが、Node.js用に提供されているパッケージを使うことができます。今回の解説では、データベース処理の実装方法をざっくりと把握することを目的として、手短に実装できるSQLiteと、SequelizeというORMを使います。
3.1 Sequelize
SequelizeはNode.js用のORMです。ORMとはObject-Relational Mapping の略で、サーバーサイドのオブジェクト実装と、リレーショナルデータベースのマッピングをするものです。
※ORMにはメリットとデメリットがあるので、実際のプロジェクトでの導入にあたっては総合的な検討が必要だと思います。
Sequelize公式ページ:
http://docs.sequelizejs.com/
3.2 SQLite
今回は手軽に実装できるSqliteを使うことにしますが、SequelizeはMySQL、PostgreSQL、Microsoft SQL Serverをサポートしており、基本的にはどのDBでも同じような流れで使うことができます。また、Sequelize-CLIはSQLiteのインスタンスファイルを生成することができますので、SQLiteをインストールする手間も省けます。
3.3 今回作成するもの
SQLiteデータベースにUserテーブルを作成し、以下のようなカラムを持たせます。
- firstName : string
- lastName : string
- email : string
その後サンプルデータを投入して、JSON形式で出力するところまで作成します。
3.4 パッケージのインストール
以下の3つのパッケージをインストールします。
・sequelize(v5.8.10)
・sequelize-cli (v5.5.0)
・sqlite3 (v4.0.9)
1 | npm install --save sequelize sequelize-cli sqlite3 |
3.5 Sequlize-CLIを使ったセットアップ
今回Sequelize-CLIで行うことは大きく4つあります。
(1) DB接続設定
(2) Modelファイル生成、Migrationファイル生成
(3) Migration実行
(4) サンプルデータ生成/投入
Modelファイルというのはサーバーサイドのクラスファイルのようなもので、DBのカラムと同じ情報を持つように構成されます。またMigrationというのは、データベースのテーブルなどを作成することです。(1)〜(4)の中で、ポイントとなるのは(2)の操作です。(2)の操作によって、サーバーサイドとデータベースの両方に対し、1対のペアになるようなデータ構造を実現するためのスクリプトが生成されます。
Sequlize-CLIでの操作概要を把握できたと思いますので、実際にコマンドを実行していきましょう。
(1) DB接続設定
先ず、sequelizeプロジェクトを初期化します。
1 | npx sequelize init |
成功すると以下の4つのディレクトリが生成され、完了メッセージが表示されます。
- config
- models
- migrations
- seeders
1 | Created "config/config.json" |
configファイル編集
次に./config/config.json を編集してDB接続設定を行います。config.jsonは初期状態では以下のようにMySQLの設定例が記載されています。JSONデータがdevelopment / test / production の3つの部分に分かれており、それぞれの実行環境でデータベースを使い分けられるようになっています。実行環境の指定は環境変数のNODE_ENV
で行います。NODE_ENV
が未設定の場合はデフォルトでdevelopmentの記述が使用されます。
1 | { |
項目 | 値 | 意味 |
---|---|---|
dialect | sqlite | DB種別はSQLite |
strage | ./myapp.sqlite3 | DBインスタンスは./myapp.sqlite3 |
(2) Modelファイル生成、Migrationファイル生成
この操作はORMにとってカギとなる重要な場面なので、実際のプロジェクトでは慎重に行う必要があります。予めデータベースのテーブルやカラムなどの設計をしておく必要があります。いったんこの操作を実行した後で、しばらくしてテーブル名などを変更しようとすると、ソースコードのいろいろな箇所を修正する必要が出て何かと面倒です。
Sequelize-CLIのmodel:generate
というコマンドを使います。
1 | sequelize model:generate --name [モデル名]--attributes [メンバ情報] |
パラメータにモデル名やメンバ情報を指定します。「モデル名」というのはサーバーサイドでの呼び方であり、データベース側では「テーブル名」ということになります。また同じく「メンバ情報」というのはデータベース側では「カラム情報」ということになります。このように、同じ名前をサーバー側とデータベース側で共有するというところがORMが「Object-Relational Mapping」であるためのポイントでもあります。
オプション | 値 | サーバーサイド | DB側 |
---|---|---|---|
–name | User | モデル名 | テーブル名 |
–attributes | firstName:string, lastName:string, email:string |
メンバ情報 | カラム情報 |
以下のようにコマンドを実行します。
1 | npx sequelize model:generate --name User --attributes firstName:string,lastName:string,email:string |
コマンドを実行すると、User情報に関する2つのjsファイルが生成されます。1つは、サーバーサイドでUser情報を格納するためのモデル定義のModelファイル。もうひとつはデータベースでUserテーブルを生成するためのMigrationファイルです。
コマンドの実行が成功すると以下のように出力されます。
1 | New model was created at /(プロジェクトフォルダ)/myapp/models/user.js . |
お時間のある方は生成されたjsファイルの中身を見てみましょう。お急ぎの方は次の「(3) Migration実行」へお進みください。
Modelファイルを見てみる
/models/user.jsを開いてみると以下のようになっています。先ほどパラメータで指定した情報があっさりとオブジェクトとして定義されています。
1 | ; |
Sequelizeが生成したモデルファイルは、全体としてはmodule.exportsでエクスポートされて、Userオブジェクトを返す構造になっています。(Nodeが初めての方へ:Node.jsのmodule.exportsはES6のexport文とは異なりますので軽くご注意ください。)
1 | module.exports = function(sequelize, DataTypes){ |
このようにexportされたモジュールなので、読み込む側では、うっかり以下のように書いてしまいそうです。
1 | // 誤った読み込み方 |
しかし実際は、もう1つ上の階層を使ってrequire('../models/')
とします。
1 | // 正しい読み込み方 |
どうしてこのような多段階のモジュール構成になるのかというと、Sequelizeは初期化のときに/models/index.jsという、親モジュールになるモジュールを生成していて、そのモジュールが/models/ディレクトリにある全てのモジュールを読み込み込んだ上で、読み込んだUserモジュールなどにfindAll()
などのメソッドを付け加えるという処理をしているからです。
1 | // modelsディレクトリの中のファイルを探して読み込む箇所 |
Migrationファイルを見てみる
続いて、/migrations/(現在日付)-create-user.jsを見てみましょう。このファイルもModelファイルと同じようにmodule.exportsでエクスポートされています。
1 | ; |
ざっと眺めて先ほどのModelファイルより情報量が多い理由としては、Migrationはデータベースを操作するためのものなので、カラムの制約に関する指定(Nullを許可、autoIncrement、primaryKeyなど)があるということと、DB用カラムのcreatedAt
(レコード作成日時)、updatedAt
(レコード更新日時)などが存在していることが挙げられます。
また、”up”と”down”の2つの部分に分かれていますが、downにはupの操作を取り消す(revert)ための操作を書くことができます。例えば “up”が「テーブル作成」ならば、これに対する”down”は「テーブル削除」に相当する操作を記述します。
データの型などを詳細に指定することもできます。例えば、Sequelize.STRING
はデフォルトで VARCHAR(255)
になりますがこの値を変更することができます。
Sequelizeの公式サイトに詳細な情報があります。(英語)
http://docs.sequelizejs.com/manual/migrations.html
(3) Migration実行
それではMigrationを実行しましょう。MigrationとはDBの定義ファイルにしたがってDBやテーブルなどを作成することです。Migrationの背後では、SQL文の CREATE TABLE
などが実行されます。
1 | npx sequelize db:migrate |
成功すると以下のように出力されます。
1 | Loaded configuration file "config/config.json". |
Migrationの背後では、例えば以下のようなSQLが実行されています。
1 | CREATE TABLE `Users` ( |
ここまでの段階で、SQLiteのデータベースファイルが作成されました。
DB Browser for SQLiteなどのGUIツールで確認してみましょう。
https://sqlitebrowser.org/
(4) サンプルデータ生成/投入
続いてサンプルデータを作成して、投入していきます。
1 | npx sequelize seed:generate --name seed-user |
成功すると以下のように出力されます。
1 | New seed was created at /(プロジェクトフォルダ)/myapp/seeders/(現在日付)-seed-user.js . |
./seeders/(現在日付)-seed-user.jsを開いて以下のように編集します。
1 | ; |
サンプルデータを投入
1 | npx sequelize db:seed:all |
成功すると以下のように出力されます。
1 | Loaded configuration file "config/config.json". |
GUIツールで確認してみます。
データが挿入されていれば成功です。
3.6 JSON形式で出力する
データベースへの接続準備が整いましたので、アプリケーションから接続してデータを取得してみましょう。今回は、簡単に書くために./routes/users.jsというルーティング用のファイルの中に直接書く方法で行います。(次回のレッスンではMVCアーキテクチャでデータを取得して表示する方法を学びます。)
データベースのデータを読み込む
先ずデータを読み込む部分ですが、これは次の1行を書くだけです。
1 | var db = require('../models/'); |
次に、データを出力する部分は以下のようになります。
1 | // ユーザーのリストをJSON出力する |
それぞれの行の意味を簡単に説明します。
1 | 1: // ユーザーのリストをJSON出力する |
これは、/user/json/というリクエストに対するハンドラを定義しています。前回のレッスンでも学びました。
1 | 4: // Sequelizeのモデルを使ってデータを取得する |
ここでは、SequlizeのfindAll()
メソッドを使って、データベースのUserテーブルからデータを取得しています。背後では、SQLのSELECT文が実行されます。Sequlizeに限らずNodeでのDBデータ取得は非同期で行われるので、データを取得した後の処理はCallbackかPromiseなどの仕組みを使います。SequlizeのメソッドはPromiseを返すので、成功した場合は.then()
で受けます。.then(function(users){})
という形でパラメータとして取得したデータを受け取ります。
1 | 7: if (!users) { |
ここでは、.then()
で受け取ったusersデータが空(nullやundefined)かチェックしています。空の場合はエラーを返しています。
1 | 11: //レスポンスを返す |
responsオブジェクトのjson()メソッドを使って、取得したデータをJSON形式で返しています。
以上の処理を./routes/users.jsに記述すると全体としては以下のようになります。
1 | var express = require('express'); |
アプリを起動して確認する
それではアプリを起動して確認してみましょう。
1 | npm start |
ブラウザで次のURLにアクセスします。
以下のようにJOSNデータが表示されれば成功です。
まとめ
Sequlize-CLIを使ってDB実装を行いました。その中で以下のようなコマンドを使いました。
1 | npm install --save sequelize sequelize-cli sqlite3 |
また、DBのデータをJSONで出力させるために、以下の関数を ./routes/users.jsに追加しました。
1 | /* ユーザーのリストをJSON出力する */ |
次回はMVCアーキテクチャについて学びます。