SequelizeでHerokuのPostgreSQL接続

DBとのデータのやり取りでSequelizeを使うことにしました。 いろいろハマったのでメモ代わりに残しておきます。

目的

  • SequelizeでHeroku上のPostgreSQLにデータをinsert、select、deleteする。

インストール

Sequelizeをインストールします。

$ npm install --save sequelize

DBがPostgreなのでpg, pg-hstoreをインストールします。

$ npm install --save pg pg-hstore

使っているDBがPostgre以外の場合には、使っているDBに合わせてライブラリをインストールしてください。 インストールしなければならないライブラリはSequelizeの公式サイト(Manual | Sequelize)に載っています。

使用方法

テーブルの作成

データベースに次のようなテーブルを作成したとします。

/* create-table.sql */
create table schema.users (
    id         serial,
    created_at  timestamp with time zone not null default current_timestamp,
    updated_at timestamp with time zone not null default current_timestamp,
    primary key(id)
);

Sequelize:モデルの作成

まずはこのtableにアクセスするためのモデルを作成します。

/* models/user.js */
const Sequelize = require("sequelize");

class User extends Sequelize.Model {
    static init(sequelize) {
        return super.init({
            id: {
                type: Sequelize.INTEGER,
                primaryKey: true,
                autoIncrement: true,
            },
            created_at: Sequelize.DATE,
            updated_at: Sequelize.DATE,
        }, {
            schema: 'schema',
            tableName: 'users',
            timestamps: false,
            freezeTableName: true,
            sequelize ,
        })
    }
}

module.exports = User;

serial型のidには「autoIncrement: true」を指定が必要です。指定しないとinsert時に次のようなエラーを吐きます。

Unhandled rejection SequelizeDatabaseError: null value in column "id" violates not-null constraint

PostgreSQLのserial型はnot null相当なので何の値も指定していないと、Sequelizeがエラーを吐くわけです。autoIncrementを指定することによってSequelizeに自動採番である旨を定義することができ、エラーを吐かなくなります。

Sequelize: データベース接続 & insert/select/destroy

次に実際にモデルを使用してみます。

/* user.js */
var pg = require('pg');
pg.defaults.ssl = true;
const Sequelize = require('sequelize');
const User = require('models/user');

function databaseTest(request) {
    const seq = new Sequelize(
        // 「heroku config -a (アプリ名)」で出てきた「DATABASE_URL」の値を記入
        'postgres://(user):(password)@(host):(port)/(database)',
    );
   // さっき宣言したモデルの呼び出し
    const user = User.init(seq);

    var current = new Date();

    // データをinsert
    user.create({
        created_at: current,
        updated_at: current,
    })
    .then((result) => Promise.resolve(result.id))
    // データをselect
    .then((userId) => user.findOne({
        where: {
            id: userId
        }
    }))
    .then((result) => {
        console.log(result)
        return Promise.resolve(result.dataValues.id)
    })
    // データをdestroy
    .then((userId) => user.destroy({
        where: {
            id: userId
        }
    }));
}

databaseTest();

pg.default.sslをtrueにセットする必要があったのですが、それに気がつかず、エラーで何度もハマりました。

さて、これで最低限アクセスできるようになりました。

今回はやっていないけれどちゃんとトランザクション張った処理もできます。 Promiseで返ってくるから同期処理もやりやすいし、クラス定義っぽくアクセスできるし便利。