なんだかGoodVibes

日々の勉強メモです。

【Node】MYSQLの操作(Bookshelf)

前回、MYSQLを操作する記事を上げました。
でも、正直あれってめんどくさいですよね。
今回は、もっと便利なBookshelfをご紹介します。
前回の記事は以下です。

nandakagoodvibes.hatenablog.com



Bookshelfって何?

複数のデータベースに対応していて
設定1つで指定したデータベースが使用できます。
使用するにあたってインストールが必要なモジュールは以下。

  • knex:SQLのクリエーを生成するためのモジュール
  • bookshelf:データベースアクセスを行うBookshelf本体

npmでインストールしてください。


サンプルについて

-- app.js
-- public
    -- style.css
-- router
    -- index.js
-- views
    -- allshow.ejs
    -- create.ejs
    -- find.ejs
    -- head.ejs

今回は、index.jsにまとめて処理を書いていきます。


app.js

var express = require('express');
var indexRouter = require('./router/index');
var bodyParser = require('body-parser');

var app = express();
app.use(bodyParser.urlencoded({extended : false}));
app.use('/', indexRouter);
app.set('view engine', 'ejs');
app.use(express.static('public'));

var server = app.listen(3000, () => {
    console.log('Server Start!');
});


index.js

各項目に分けて記載していきます。


共通設定

index.jsの最初に記載する内容です。
今回インストールした2つモジュールを読み込んでいます。
var knex = …でデータベースの設定をしています。
今回新規の項目はclientとcharsetですね。

var MyData = …でテープルにアクセスするオブジェクトを作成します。

var express = require('express');
var router = express.Router();

var knex = require('knex')({
    client: 'mysql',
    connection: {
                host     : 'ホスト',
                user     : 'ユーザー',
                password : 'パスワード',
                database : '対象のデータベース'
                charset  : 'utf8'
    }
});

var Bookshelf = require('bookshelf')(knex);

var MyData = Bookshelf.Model.extend({
    tableName: 'テーブル名'
});


ALLSHOW(すべてのレコードを表示する)

前回紹介した処理と比べると、とてもシンプルですね。


new MyData()…での処理は以下の内容です。

  • fetchAll: すべてのレコードを取得。
  • then: データベースアクセス完了後の処理。コールバック関数。
  • collection: データベース取り出しの結果。「BaseModel」オブジェクトの配列

処理に失敗した場合に備えて、エラーキャッチもしています。

router.get('/',(req, res, next) => {

    new MyData().fetchAll().then((collection) => {

        var data = {
            title: 'ALLSHOW',
            content: collection.toArray()
        };

        res.render('allshow.ejs', data);
    })
    .catch((err) => {

        res.status(500).json({
            error: true,
            data: {message: err.message}
        });
    });
});


表示テンプレートは以下です。(表示部分のみの記載とします)
配列をループで回して出力しています。
対象の値達はBookModelオブジェクトの「attributes」プロパティに格納されています。

<div role="main">
    <table>
    <% for(var i in content) { %>
    <tr>
        <% var obj = content[i].attributes; %>
        <th><%= obj.id %></th>
        <td><%= obj.name %></td>
        <td><%= obj.mail %></td>
        <td><%= obj.age %></td>
    </tr>
    <% } %>
    </table>
</div>


CREATE(新規に作成する)

new MyData()…での処理は
入力された値を保存(新規作成)しています。
こちらもエラーチェックを行っています。

router.get('/create', (req, res, next) => {

    var data = {
        title: 'CREATE',
        content: '新しいレコードを入力:'
    };

    res.render('create.ejs', data);
});

router.post('/create', (req, res, next) => {

    var response = res;

    new MyData(req.body).save().then((model) => {
        response.redirect(('/'));
    })
    .catch((err) => {

        var data = {
            title: 'CREATE',
            content: '作成処理に失敗しました。'
        };

        res.render('create.ejs', data);
    });
});


表示テンプレートは以下です。(表示部分のみの記載とします)
入力フォームを表示しています。

<div role="main">
    <p><%= content %></p>
    <form method="post" action="/create">
    <table>
        <tr>
            <th>NAME</th>
            <td><input type="text" name="name"></td>
        </tr>
        <tr>
            <th>MAIL</th>
            <td><input type="text" name="mail"></td>
        </tr>
        <tr>
            <th>AGE</th>
            <td><input type="number" name="age"></td>
        </tr>
        <tr>
            <th></th>
            <td><input type="submit" value="作成"></td>
        </tr>
    </table>
    </form>
</div>


FIND(IDで検索を行う)

こちらは今回初登場ですね。
指定のIDをフォームで送信して
そのレコードを検索するページです。


new MyData()…での処理は以下の内容です。

  • where: 絞り込みを行う。(第1引数=項目名、第2引数=比較する記号、第3引数=値)
  • fetch: 最初の1つ目だけ取り出す。BaseModelが取り出される。

検索ではIDが一意であるので、fetchを使用しています。
登録されていないIDを指定された場合、エラーとなります。
その場合はエラーキャッチの処理で吸収しています。

router.get('/find', (req, res, next) => {

    var data = {
        title: 'FIND',
        content: '検索するIDを入力してください。',
        form: {id: ''},
        mydata: null
    };

    res.render('find.ejs', data);
});


router.post('/find', (req, res, next) => {

    new MyData()
        .where('id', '=', req.body.id)
        .fetch()
        .then(collection => {
            var taishoId = req.body.id;
            var data = {
                title: 'FIND',
                content: 'id= ' + taishoId + 'の検索結果。',
                form: req.body,
                mydata: collection
            };

            res.render('find.ejs', data);
    })
    .catch((err) => {

        var data = {
            title: 'FIND',
            content: '検索に失敗しました。再度入力してください。',
            form: {id: ''},
            mydata: null
        };

        res.render('find.ejs', data);
    });
});


表示テンプレートは以下です。(表示部分のみの記載とします)
対象のIDのレコードが存在している場合のみテーブルを表示しています。

<div role="main">
    <p><%- content %></p>
    <% if (mydata != null) { %>
    <p><ul>
        <li><%- mydata.id %></li>
        <li><%- mydata.attributes.name %></li>
        <li><%- mydata.attributes.mail %></li>
        <li><%- mydata.attributes.age %></li>
    </ul></p>
    <% } %>
    <form method="post" action="/find">
    <table>
        <tr>
            <th>ID</th>
            <td><input type="text" name='id' value="<%= form.id %>"></td>
        </tr>
        <tr>
            <th></th>
            <td><input type="submit" value="検索"></td>
        </tr>
    </table>
    </form>
</div>


まとめ

どうだったでしょうか。
非常に簡単に記載することができますね。
今回は以上です。