はじめに
GridDBは近年非常に人気のあるnode.jsとのデータベースコネクタをリリースしました。これはGo言語コネクタと同様に、SWIG ライブラリで構築されています。 node.jsクライアントは、CentOS 6および7で動作するnode.jsバージョン6をサポートしています。
Node.jsが2009年の最初にリリースされてから、JavaScriptは10年の間世界で最も使われるプログラミング言語の座についてきましたが、その要因の一つはNode.js と言えるでしょう。開発分野では依然としてnode.jsの重要性が高いため、このコネクタを構築することはかねてからGridDBチームの最優先事項となっていました。
このブログでは、GridDBのデータベースコネクタのインストール、設定、テストまでの手順をご紹介します。
Table of Contents
Node.jsクライアントのセットアップとインストール
システム上にNode クライアントをビルドするには、まずGridDB C クライアントをビルドしインストールする必要があります。 あまり詳しくない方は、このブログに沿って、Cクライアントの設定とテストの方法を実行することができます。 GitHubページにも簡単な説明があります。
Cクライアントが動作していることが確認されたら、次にnode.jsクライアントのGitHubリポジトリをクローンします。
$ git clone https://github.com/griddb/nodejs_client
ここまででGitHubからソースコードを入手したので、次にNode.jsクライアントのGithub ページのREADME
の中のインストラクションに従います。
GitHubの公式README文書によると、node.jsクライアントをビルドする前に、SWIGとPCREの両方をビルドし、動作確認する必要があります。
$ wget https://sourceforge.net/projects/pcre/files/pcre/8.39/pcre-8.39.tar.gz $ tar xvfz pcre-8.39.tar.gz $ cd pcre-8.39 $ ./configure $ make $ make install $ wget https://prdownloads.sourceforge.net/swig/swig-3.0.12.tar.gz $ tar xvfz swig-3.0.12.tar.gz $ cd swig-3.0.12 $ ./configure $ make $ make install
Node.jsクライアントのビルド時に起こりうる問題
場合によっては、Node.jsクライアントパッケージで make
を発行するときに以下のようなエラーが発生することがあります。
$ make error while loading shared libraries: libpcre.so.1: cannot open shared object file: No such file or directory
これは、これまでの手順に問題がある可能性があります。 node.js_clientのGitHubインストラクションに従って進める場合は、makeする前にpcreとswigをインストールしておく必要があります。 そうしないとLIBRARY_PATHがpcreを指さず、SWIGライブラリを動作させることができないといった問題が発生する可能性があります。 これが該当するかどうかは、以下のような簡単なテストで確かめることができます。
$ swig -version swig: error while loading shared libraries: libpcre.so.1: cannot open shared object file: No such file or directory
このエラーがポップアップする場合は、次のコマンドを実行します。
$ find / -name libpcre.so.1
ファイルの場所をメモします。 場所が分かったら、以下を実行します。
$ export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH
swig -version
というコマンドが機能するようになりました。 もう一度makeをやり直してみてください。
以下のような問題が起こる場合:
g++ -fPIC -std=c++0x -g -O2 -Iinclude -Isrc -Iusr/include/node -DNODE_GYP_MODULE_NAME=griddb -DV8_DEPRECATION_WARNINGS=1 -DBUILDING_NODE_EXTENSION -c -o src/griddb_js.o src/griddb_js.cxx src/griddb_js.cxx:171:18: fatal error: node.h: No such file or directory #include^ compilation terminated. make: *** [src/griddb_js.o] Error 1
node.js開発ツールをインストールし、Makefileを編集してnode.hファイルの場所を変更する必要があるかもしれません。
$ sudo yum install nodejs-devel $ cd ~/nodejs_client $ vi Makefile INCLUDES_JS += -I/usr/include/node
これでnode.jsクライアントが正しくコンパイルされるはずです。 もしこれ以外の問題が発生した場合は、フォーラムに投稿してサポートを受けてください。
JavaScriptを使用したGridDBへの接続
ここまでで準備作業が完了したので、JavaScriptを使ってGridDBに接続することができるようになりました。 これ以降は他のパッケージと同じプロセス( “require”)です。
GridDBインスタンスの接続例を示します。
var griddb = require('griddb_node'); var fs = require('fs'); var factory = griddb.StoreFactory.getInstance(); var store = factory.getStore({ "host": process.argv[2], "port": process.argv[3], "cluster_name": process.argv[4], "username": process.argv[5], "password": process.argv[6]});
最初の2行は標準のnode.js定型文です。 変数store
は、node.jsコマンドライン(CL)引数を使用します。 一般的なノードファイルを実行するときは、端末で以下を実行します。
$ node file1.js
このように、GridDBクラスタに接続してコードを同時に実行するには、CL引数を実装する必要があります。
$ node blog.js 239.0.0.1 31999 temperature admin admin
スキーマとコンテナの作成
コンテナと行のスキーマは、store.putContainer
オブジェクトとともにgriddb.ContainerInfo
オブジェクトを呼び出すことによって作成されます。 詳細については、node.js API リファレンスを参照してください。
たとえば、新しいコンテナを作成するには、最初にgriddb.ContainerInfo
オブジェクトの新しいインスタンスを作成して列タイプを設定します。
var conInfo = new griddb.ContainerInfo("col01", [ ["name", griddb.GS_TYPE_STRING], ["status", griddb.GS_TYPE_BOOL], ["count", griddb.GS_TYPE_LONG], ["lob", griddb.GS_TYPE_BLOB] ], griddb.GS_CONTAINER_COLLECTION, true)
最初のパラメータstring
はコンテナ名です。 残りは、その列の型と名前です。
行は、griddb.Container put
メソッドを利用して列に追加することができます。
例えば、
var col2; store.putContainer(conInfo, false) .then(col => { col2 = col; col.createIndex("count", griddb.GS_INDEX_FLAG_DEFAULT); return col; }) .then(col => { col.setAutoCommit(false); col.put(["name01", false, 1, "ABCDEFGHIJ"]); return col; }) // 以下は省略します。
putContainer
メソッドの最初のパラメータはコンテナ情報(conInfo
) をとります。 次に、JavaScript promisesを処理してインデックスを作成し、列とデータを設定します 。 col.put
は、STRING
型の “name”という列にデータ行を明示的に配置しています。
データのクエリと取得
コンテナにデータが格納され、GridDBに挿入されると、データのクエリとフェッチが可能になります。 PythonやJava APIと同様に、コンテナに対し発行したいTQLクエリを使ってQueryオブジェクト(またはgriddb_go.Query
型)を構築します。 これが完了したら、クエリの結果を取得してgriddb_go.RowSet
オブジェクトに格納します。
コンテナに関連するデータが入力されると、次のステップが必ずクエリーされます。 node.jsクライアントAPIを使用してデータを照会するには、container
オブジェクトからquery
メソッドを呼び出します。 GridDBは、SQLに似た言語TQLを使用してクエリを実行します。 例えば:
var col2; store.putContainer(conInfo, false) .then(col => { col2 = col; col.createIndex("count", griddb.GS_INDEX_FLAG_DEFAULT); return col; }) .then(col => { col.setAutoCommit(false); col.put(["name01", false, 1, "ABCDEFGHIJ"]); return col; }) .then(col => { col.commit(); //commits calls are required to commit the current transaction and start a new transaction return col; }) .then(col => { // container.query takes the raw TQL query = col.query("select *"); // the fetch method returns the results in the form of RowSet return query.fetch(); }) .then(rs => { // RowSet is the result from the query.fetch while (rs.hasNext()) { // While the row has another row after the current console.log(rs.next());//print that row } col2.commit(); }) .catch(err => { console.log(err.what()); for (var i = 0; i < err.getErrorStackSize(); i++) { console.log("[", i, "]"); console.log(err.getErrorCode(i)); console.log(err.getMessage(i)); } });
上記のコードスニペットには、関連する部分を説明するコメントがあります。 GridDBのコンテナ/カラムをクエリするには、query
メソッドとfetch
メソッドの組み合わせを、RowSetオブジェクトの next()
メソッドとともに使用する必要があります。
クライアントがクエリの結果を返すと、RowSet promiseが返されます。 このpromiseより、典型的なワークフローは、 while
ループを実行し、 while
RowSet.hasNext()
をチェックし RowSet.next()
をプリントします。
集計TQL
TQLを使用して集約クエリを作成して発行することもできます。 コンテナからgriddb_go.AggregationResult
を実行してフェッチする方法は、Python APIによく似ており、クエリからRowSet を取得したら、rowSet.NextRow()
を使用する代わりに、.NextAggregation()
に変更します。そのAggregationResult
オブジェクトでは、必要な番号の型を取得するために.Get()
を使用します。
TQLでは、集約クエリを発行する機能も使用できます。 これを行うには、適切な集約操作を使用して生のTQLクエリを発行します。
例えば:
var timeseries; store.getContainer("point01") .then(ts => { timeseries = ts; query = ts.query("select * from point01 where not active and voltage > 50"); return query.fetch(); }) .then(rowset => { var row; while (rowset.hasNext()) { row = rowset.next(); var timestamp = Date.parse(row[0]); aggCommand = "select AVG(voltage) from point01 where timestamp > TIMESTAMPADD(MINUTE, TO_TIMESTAMP_MS(" + timestamp + "), -10) AND timestamp < TIMESTAMPADD(MINUTE, TO_TIMESTAMP_MS(" + timestamp + "), 10)"; aggQuery = timeseries.query(aggCommand); aggQuery.fetch() .then(aggRs => { while (aggRs.hasNext()) { aggResult = aggRs.next(); console.log("[Timestamp = " + timestamp + "] Average voltage = "+ aggResult.get(griddb.GS_TYPE_DOUBLE)); } }); } })
上記の例のように、集計結果を照会し実行する準備ができたら、APIには特別なAggregationResult.get(Type type)
メソッドがあります。
タイムスタンプデータの処理
GridDBはTimeSeriesデータを重視し、IoTにおける優位性を狙ったデータベースであるため、TimeSeriesデータを処理する手段が必要です。幸いなことに、JavaScriptはタイムスタンプを持つデータの処理にすでに対応しているため、 特別な機能は必要ありません。
結論
ブログはこれで以上です。このブログが、みなさんがnode.jsとGridDBを使って開発を始める際に役立つことを期待しています。 何かご不明な点があれば、 GridDBフォーラムで質問してください。
参照
- このブログでは、CentOS 6.9 operating system上で Node.js バージョン 6.14.3が使用されました。
- このブログでは、GridDBデータベースとしてGridDB Community Edition 3.0.1を使用しました。
- GridDB node.jsクライアントのソースコードは、official Github repositoryにあります。
- このリファレンスページ にnode.jsクライアントでアクセスできるGridDBのすべてのオブジェクトとリソースが記載されています。
ソースコード
このブログで使用したすべてのソースコードは、 GitHub pageにあります。
ブログの内容について疑問や質問がある場合は Q&A サイトである Stack Overflow に質問を投稿しましょう。 GridDB 開発者やエンジニアから速やかな回答が得られるようにするためにも "griddb" タグをつけることをお忘れなく。 https://stackoverflow.com/questions/ask?tags=griddb