Express.jsサーバでSequelize.jsを使ってMySQLデータベースとやりとりさせる

Nodeにはrailsのようにデータベースを管理できるモジュールであるsequelizeがあります。 expressで開発をやっていると、railsがどれだけ便利だったのかを思い知らされますね笑

expressでアプリケーション開発

https://gist.github.com/mitsuruog/fc48397a8e80f051a145

ざっと説明すると、

$ npm install -g express-generator
$ express --view=pug your-app-name
$ cd your-app-name
$ npm install
$ npm start

云々、ということです。

mysqlの導入

この前expressでpassport認証する際にmysqlを導入する内容を書いたのでそっちをみてみてください。 https://qiita.com/y4u0t2a1r0/items/db6c39e9dcea21f8e994 ググればすぐです。

sequelize

cliで利用するためにsequelize-cliをグローバルでインストールします。

$ npm install -g sequelize-cli
$ npm install --save sequelize

仕事場の環境上、windowsで仮想環境(vagrant)を立ち上げて開発を行なっていたのですが、 windowsの場合、シンボリックリンクが貼れずにnpm installがうまくいかないことがあるので、 もしnpm installでエラーが発生したら、

$ npm install -g sequelize-cli --no-bin-links
$ npm install --save sequelize --no-bin-links

という感じで--no-bin-linksをつけてあげてください。 http://eiua-memo.tumblr.com/post/117361529158/npmvagrantvagrant%E3%81%AE%E5%85%B1%E6%9C%89%E3%83%95%E3%82%A9%E3%83%AB%E3%83%80%E4%B8%8A%E3%81%A7npm

で、うまくインストールできたら、railsチックにデータベースを作成していきましょう!

$ sequelize init

initしてあげると、アプリケーションのディレクトリに、 config, migration, model の3つのディレクトリが作成されます。

migration, modelのディレクトリにはまだ何も入っていませんが、 configディレクトリ内にはconfig.jsonなるものがあります。

# config.json

{
  "development": {
    "username": "root",
    "password": null,
    "database": "database_development",
    "host": "127.0.0.1",
    "dialect": "mysql"
  },
  "test": {
    "username": "root",
    "password": null,
    "database": "database_test",
    "host": "127.0.0.1",
    "dialect": "mysql"
  },
  "production": {
    "username": "root",
    "password": null,
    "database": "database_production",
    "host": "127.0.0.1",
    "dialect": "mysql"
  }
}

こんな感じになっているので、利用する用途に合わせて、 mysqlのパスワードや利用するデータベースの名前(任意)、ホスト(ローカルホストならlocalhost)を書いてあげます。

 まずはデータベースを作成しましょう。

$ sequelize db:create

これで先ほどconfig.jsonに書き込んだdatabaseを作成します。 次のコマンドたちもよく使いますのでメモ。

$ sequelize db:drop # dbを落とす
$ sequelize db:create # dbを作成
$ sequelize db:migrate # migrate実行
$ sequelize db:migrate:undo:all # 実行されたmigrateを全て取り消し
$ sequelize db:seed:all # 設定されていたseedファイルをmigrate
$ seqeulize db:seed:undo:all # seedファイルのmigrateを全て取り消し

次に、例としてusername(type=string), age(type=integer)のカラムを持つuserテーブルを作成します。

$ sequelize model:create --underscored --name user --attributes "user_name:string,age:integer"

railsみたいにmodelを作成できて、最初感動しました笑 ですが、sequelizeではrailsのように外部キーなどをcli上で指定することはないっぽいです。 基本的にmodel:createで作成されるmigrationファイルに外部制約などを設定してdb:migrateする感じですね。

// app/migrations/migration_file.js

user_id: {
  allowNull: false,
  references: {
    model: 'users',
    key: 'id'
  },
  type: Sequelize.INTEGER
}

上のコードはuserの子テーブルに定義されたuser_idカラムの設定を想定しています。 references:{}の中に親のmodelとその参照するkeyを設定します。

associationについて、公式で色々読めるので細かいところはそっちを参考にしてみてください。 http://docs.sequelizejs.com/manual/tutorial/associations.html

多対多のテーブルを作成する場合も、

$ sequelize model:create --underscored --name communities_users --attributes "community_id:integer, user_id:integer"

このように外部キーであるカラムを用意しておいて、migrationファイル内にreferencesを設定していきます。 (例としてusersを複数要するcommunitiesとcommunitiesを複数要するusersの中間テーブルを考えています) modelにも、hasManyやbelongsToなどを定義してあげれば良いです。 中間テーブルの場合throughで関係を持たせてあげればオッケーです。

この点も公式のassociationの項目を参考にしてみてください。 http://docs.sequelizejs.com/manual/tutorial/associations.html#belongsto

sequelizeでCRUD

mysqlをexpressで使うと、

// app.js

let mysql = require('mysql2');
let connection = mysql.createConnection(
  host: 'localhost',
  user: 'root',
  password: '********',
  database: 'testdb'
});

connection.query('select * from users;', function(err, users) {
  console.log(users); // queryの結果が返ってくる
}

みたいな感じのを書いて、 select, insert, update, deleteを行うことになりますが、 sequelizeではこのようになります。↓

// app.js

let db = require('./models/index'); // cliでinitした時に作成されるmodels配下のindex.js

// findAll
db.users.findAll({}).then((instances) => { // usersのところが自分で作成したモデル
  console.log(instances); // usersの中身を全て取得した結果
});

// create
db.users.create({
  username: '#####',
  email: '#####@#####'
}).then((createdUser) => {
  console.log(createdUser); // 作成されたuserインスタンスの詳細
});

こんな感じでデータベース内の要素を全取得したり、作成保存したり、更新削除することができます。

ajaxでフロントからデータを飛ばして、

// front.js

$.ajax({
  url: 'users/new',
  type: 'post'
}).done((data) => { // data = サーバーから返ってきたデータ
  console.log(data);
}).fail((err) => {
  console.log(err);
});
// app.js

router.post('/new', function(req, res, next) {
  db.users.create({
    username: '#####',
    email: '#####@#####'
  }).then((createdUser) => {
    res.send(createdUser); // ajaxのdoneにdataを渡す
  }).catch((err) => {
    res.status(500).send(err);
  });
});

こんな感じにサーバーでデータベースを更新するっていうのが基本的な使い方でしょうか。