6
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

 日立製作所OSSソリューションセンタの横井一仁です。今回は、Node-REDのfunctionノードからJDBCドライバを用いて、データベースに接続する手順をご紹介します。

背景

 データベースを扱った事がある方であればご存知のように、JDBCはJavaからデータベースへ接続するための仕組みです。そのため、Node.js上で動くNode-REDから、Javaを用いてデータベースに接続することは少しトリッキーに感じるかもしれません。しかし、データベース製品やデータベースのOSS開発コミュニティから、データベースと接続するNode.jsのライブラリが提供されていない場合は、この方法を用いてデータベースに接続できるようになります。歴史のあるデータベースであればJDBCドライバを提供しているため、ほぼ全てのデータベースに適用できる方法です。本記事では、例としてPostgreSQLデータベースを使用します。

PostgreSQLの利用環境構築

 今回用いたUbuntu環境には、Node-REDやNode.jsの他に、OpenJDKとDocker環境をインストールしてあります。まずカレントディレクトリにJDBCドライバの入ったJARファイルをダウンロードします。Node-REDのプロセスから呼び出せる様に、JARファイルはカレントディレクトリに格納しました。

wget https://jdbc.postgresql.org/download/postgresql-42.3.1.jar --no-check-certificate

PostgreSQL環境は、以下のDockerコマンドを用いて構築しました。

docker run --name postgres -p 5432:5432 -e POSTGRES_PASSWORD=password -d postgres

その後、Node-REDを起動し、フローエディタを開きます。

node-red

functionノードでデータベースに接続するフロー作成

 それでは、早速フローを開発してゆきましょう。まずパレットからinjectノード、functionノード、debugノードをドラッグ&ドロップし、ワイヤーでつないで以下の様なフローを作成します。

undeployedflow2.png

functionノードのプロパティ設定には、「設定」、「初期化処理」、「コード」、「終了処理」の4つのタブが存在します。各タブ上で以下の設定やコードを記載します。

(1) 設定タブ

 外部npmモジュールとして、javaモジュールとjdbcモジュールを利用するため、以下の様にモジュール一覧の中に追加します。

config2.png

 javaモジュールは、Node.js上でJavaのコードを記載できるようにするためのnpmモジュールです。今回はクラスパスを設定するだけのために用いました。またjdbcモジュールは、その名前の通り、JDBCドライバを用いてNode.jsからデータベースに接続するためのnpmモジュールです。

(2) 初期化処理タブ

 初期化処理のタブのコードは、デプロイボタンを押してフローが開始された時に実行されます。ここにデータベースと接続するための初期化処理を記載します。

init2.png

記載するコード

cn = null;

// JDBCドライバの入ったJARファイルをクラスパスに追加
if (!java.classpath.includes('postgresql-42.3.1.jar')) {
    java.classpath.push.apply(java.classpath, ['postgresql-42.3.1.jar']);
}

// データベースの接続設定
var db = new jdbc({
    url: 'jdbc:postgresql://127.0.0.1/', // 接続先
    user: 'postgres', // ユーザ名
    password: 'password' // パスワード
});

// データベース接続処理
db.reserve(function (err, conn) {
    if (err) {
        // エラー内容をデバック出力
        node.error(err);
        // エラー時はステータスに「disconnected」と表示
        node.status({fill: 'red', shape: 'ring', text: 'disconnected' });
    } else {
        cn = conn;
        db.initialize(function (err) {
            // 接続時はステータスに「connected」と表示
            node.status({fill: 'green', shape: 'dot', text: 'connected' });
        });
    }
});

 4、5行名「postgresql-42.3.1.jar」は、前の手順でカレントディレクトリに配置したPostgreSQLのJDBCドライバが入ったJARファイルです。ます。もし、OracleデータベースなどPostgreSQL以外のデータベースと接続したい場合は、データベース用のJDBCドライバが入ったJARファイルを用意し、そのファイルパスを指定してください。

 また、10~12行目には接続先のURL「jdbc:postgresql://127.0.0.1/」、ユーザ名「postgres」、パスワード「password」を指定しています。こちらも他のデータベースを用いる場合は、そのデータベースに合った設定に書き換えてください。

(3) コードタブ

 「コード」タブ内には、SQL文を実行するコードを記載します。

code2.png

記載するコード

if (cn) {
    // データベース問合せ中は、ステータスに「requesting」と表示
    node.status({fill: 'blue', shape: 'dot', text: 'requesting' });
    cn.conn.createStatement(function (err, statement) {
        if (typeof msg.payload === 'string') {
            if (msg.payload.match(/^select/i)) { // SELECT文の場合
                // データベースの問合せ実行
                statement.executeQuery(msg.payload, function (err, resultset) {
                    if (err) {
                        // エラー内容をデバック出力
                        node.error(err);
                        // エラー時はステータスに「error」と表示
                        node.status({fill: 'red', shape: 'ring', text: 'error' });
                    } else {
                        resultset.toObjArray(function (err, result) {
                            msg.payload = result;
                            // 次のノードに問合せ結果を渡す
                            node.send(msg);
                            // 問合せ後、ステータス表示をクリア
                            node.status({});
                        });
                    }
                });
            } else { // SELECT文以外の場合
                // データベースの問合せ実行
                statement.executeUpdate(msg.payload, function (err, result) {
                    if (err) {
                        // エラー内容をデバック出力
                        node.error(err);
                        // エラー時はステータスに「error」と表示
                        node.status({fill: 'red', shape: 'ring', text: 'error' });
                    } else {
                        msg.payload = result;
                        // 次のノードに問合せ結果を渡す
                        node.send(msg);
                        // 問合せ後、ステータス表示をクリア
                        node.status({});
                    }
                });
            }
        } else {
            // エラー内容をデバック出力
            node.error(err);
            // エラー時はステータスに「error」と表示
            node.status({fill: 'red', shape: 'ring', text: 'error' });
        }
    });
}

 前のノードから受け取ったメッセージ中の変数msg.payload内のSQL文を実行し、結果を次のノードに渡す処理となっています。

(4) 終了処理タブ

 終了処理は、フローの再デプロイやNode-REDのプロセスの終了の前に、実行されるコードです。ここに、データベースとの切断処理を記載します。

finalize2.png

記載するコード

if (cn) {
    // データベースとの接続をクローズ
    cn.conn.close(function() {
        // 正常終了時に、ステータス表示をクリア
        node.status({});
    });
}

 デプロイボタンを押してフローをデプロイすると、javaモジュール、jdbcモジュールが自動的にインストールされます。データベースとの接続が正常に行われると、functionノードの下のステータスが緑色になり「connected」と表示されます。

connectedflow.png

functionノードを動かしてみる

 functionノードの設定が終わりましたので、早速を動かしてみましょう。injectノードのプロパティ設定で、変数msg.payloadにSQL文を書いてゆきます。

 まずは、表を作成するCREATE文です。「日時」をクリックしてプルダウンメニューを表示した後、型として「文字列」を選択します。その後、以下の様にSQL文を記載します。

createtable.png

記載するSQL文

CREATE TABLE postalcode (code INTEGER, address VARCHAR(255));

 ここでは、郵便番号と住所の対応のデータを格納する表postalcodeを作成しました。codeに郵便番号の数値を、addressに住所の文字列を格納できます。

 デプロイボタンを押した後、injectノードの左側のボタンをクリックします。正常に表を作成できると、デバッグタブには「0」という数値が表示されるでしょう。

 次は、データを登録するINSERT文です。同様に、injectノードのプロパティ設定に、郵便番号と住所を登録する以下のINSERT文を記載します。

insert.png

記載するSQL文

INSERT INTO postalcode VALUES ('2440817', 'Yokohama');

 デプロイ後、injectノードのボタンをクリックすると、先ほどと同様に、デバックタブに「1」と表示されます。これでデータの登録が完了です。

 最後に、表を検索するSELECT文です。以下の様に、表の内容を全て出力するSELECT文を記載します。

select.png

記載するSQL文

SELECT * FROM postalcode;

デプロイ後、injectノードのボタンをクリックすると、デバッグタブに、表の内容が表示されます。

selectresult.png

 もし、最初のCREATE TABLE文からやり直したい場合は、表を削除する以下のDROP TABLE文を使ってください。

記載するSQL文

DROP TABLE postalcode;

最後に

 今回は、functionノードのプロパティ画面にある「設定」、「初期化処理」、「コード」、「終了処理」の4つのタブ内の機能を使いこなして、データベースに接続するためのfunctionノードを開発しました。

 今回作成したfunctionノードをさらにサブフローでラップし、オリジナルノードを作成して公開もしておりますので、ぜひ使ってみてください。

 このオリジナルノードは、下のフローの様に今回作成したfunctionノードと同じ方法でデータベースと接続できるノードです。

jdbcnode2.png

 このノードは、以下の様なプロパティ設定画面から、JDBCドライバを自由に変更でき、接続先、ユーザ名や、パスワードをプロパティから設定できるようになっています。

jdbcnode1.png

 そのため、PostgreSQL、Oracleデータベース、その他の歴史のあるデータベースでもJDBCドライバが存在すれば、どんなデータベースとも接続することができます。試してみた方、機能改善案のある方は、ぜひ日立のGitHubリポジトリのIssueにフィードバックを頂けると嬉しいです。

商標について

  • Node-REDは、米国その他の諸国におけるOpenJS Foundationの登録商標です。
  • OracleとJavaは、米国その他の諸国におけるOracle Corporationの登録商標です。
  • その他記載の会社名、製品名などは、それぞれの会社の商標もしくは登録商標です。
6
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?