Bluemix のクラウド上で、代表的な NoSQLデータベースの Cloudant を使う簡単な Node.js の サンプルを作ってみましょう。まだの人はまず以下で Bluemix環境と Node.js アプリを準備してください。
⇒ Bluemixで作る Node.jsで動く 簡単サンプル
Cloudantの準備
ここではまず、Bluemix にCloudantのデータベースを用意します。ダッシュボードの以下の画面から、[+ サービスまたはAPIの追加] をクリックしてください。
画面を下にスクロールして、[データおよび分析] から [Cloudant NoSQL DB] をクリック。
月平均20GBの無料枠などを確認して、[作成] をクリックして作成します。[再ステージ] をクリックすると、環境を立ち上げ直して、少しすると [✔ アプリは稼動しています] になり稼動開始します。[概要] に戻り追加された以下の Cloudantをクリックしてセットアップします。
以下の右上の [Launch] (起動)をクリックして Cloudantの設定画面に。
以下の設定画面で右上の [Create Database] をクリックし、以下の例(cldb)のようにデータベース名を半角の英小文字や数字で入力します。(全角にならないように注意)
次にその cldb でデータを見つける(検索する)ための索引(キーのIndex)を作成。[All Design Docs +] で、[New Search Index] をクリックすることで索引を追加できます。
右に入力画面が表示されたら、以下のように [_design] に 「items」、[index name] に 「items_index」 とします。ここでは、キーを日付の「date」にしましょう。[Search Index Function] を以下のようにname 二箇所を 「date」 に変更し、[Save & Build Index] をクリックします。これで 「date」 をこキーにしての検索が可能になります。
次にその cldb で検索するためのビュー(取得する項目の定義)を作成。[All Design Docs +] で、[New View] をクリックすることでビューを追加できます。
以下のように既に作った 「items」 に対して、Index name 「items_view」 を追加し、その Map function (返す列のオブジェクト)を以下のように記述し [Save & Build Index] で保存してください。
function(doc) {
var row = { id: doc._id,
date: doc.date,
item1: doc.item1 };
emit(doc._id, row);
}
これで、これらの索引(Index)やビューで検索可能になります。
プログラムのCloudant対応
ダッシュボードに戻って [コードの編集] (EDIT CODE) の左のファイルから 「package.json」を選択し、以下のように変更。Cloudant にアクセスするために、Cloudantと互換性のある CouchDB 用のアクセス・モジュールである 「cradle」 を追加しています。(ここに記入することでBluemix上では自動的にモジュールがダウンロードされ組み込まれます)
{
"name": "NodejsStarterApp",
"version": "0.0.1",
"description": "A sample nodejs app for Bluemix",
"scripts": {
"start": "node app.js"
},
"dependencies": {
"express": "4.12.x",
"cfenv": "1.0.x",
"body-parser": "*",
"date-utils": "*",
"cradle": "0.6.x"
},
"repository": {},
"engines": {
"node": "0.12.x"
}
}
次に、Node.jsサーバー・アプリの、「app.js」 を以下のように変更します。。[/***ここから追加***/] のところからが、初期のサンプル・コードに対して追加した部分です。その中の青字の部分は、このページの最初のリンク先の前サンプル・アプリケーションに対して追加した部分です。Cloudantへのアクセス・モジュールである、「cradle」 を組み込み、Cloudantへの接続情報である、‘cloudantNoSQLDB’ の credentials を環境変数より取得します(後述)。
cradle.Connection を new してDBへの接続を確立し、db.save でデータ追加、db.view で全件表示、db.remove で全件削除します。
// This application uses express as its web server
// for more info, see: http://expressjs.com
var express = require('express');
// cfenv provides access to your Cloud Foundry environment
// for more info, see: https://www.npmjs.com/package/cfenv
var cfenv = require('cfenv');
// create a new express server
var app = express();
// serve the files out of ./public as our main files
app.use(express.static(__dirname + '/public'));
// get the app environment from Cloud Foundry
var appEnv = cfenv.getAppEnv();
/***ここから追加***/
// POSTパラメータ取得用 body-parser設定 (express4から必要)
var bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
// Date()で現在時刻を取得するためのユーティリティ
var dateutil = require('date-utils');
// Cloudant用アクセス・モジュール「cradle」設定
var cradle = require('cradle');
// Cloudant DB接続情報取得
var services = JSON.parse(process.env.VCAP_SERVICES);
var credentials = services['cloudantNoSQLDB'][0].credentials;
var host = credentials.host;
var port = credentials.port;
var options = {
cache : true,
raw : false,
secure : true,
auth : {
username : credentials.username,
password : credentials.password
}
};
// データベース接続
var db = new (cradle.Connection)(host, port, options).database('cldb');
app.post('/', function(req, res){
var date = new Date();
var now = date.toFormat("YYYY/MM/DD HH24:MI:SS");
req.body.date = now;
// 項目の保存
db.save(now, req.body);
res.send(req.body);
});
//「全件削除」ボタンの id=removeAll, ui_item.jsの url:'/removeAll'でcall
app.post('/removeAll', function(req, res){
// 全件検索を、作成したview名 items_view にて実行
db.view('items/items_view', function (err, rows) {
if (!err) {
rows.forEach(function (id, row) {
db.remove(id);
console.log("removed key is: %s", id);
});
} else { console.log("app.js db.remove error: " + err); }
});
res.send({});
});
//「全件表示」ボタンの id=getAll, ui_item.jsの url:'/getAll'でcall
app.post('/getAll', function(req, res){
returnTable(res);
});
var returnTable = function(res) {
// 全件検索を、作成したview名 items_view にて実行
db.view('items/items_view', function (err, rows) {
if (!err) {
rows.forEach(function (id, row) {
console.log("key: %s, row: %s", id, JSON.stringify(row));
});
} else { console.log("app.js returnTable error: " + err); }
res.send(rows);
});
}
/***ここまで追加***/
// start server on the specified port and binding host
app.listen(appEnv.port, '0.0.0.0', function() {
// print a message when the server starts listening
console.log("server starting on " + appEnv.url);
});
画面の機能追加
画面 「index.html」 は以下のように変更し、「全件表示 (getAll)」 や 「全件削除 (removeAll)」 のボタンを加えます。index.html はシンプルなままにしておきました。
<!DOCTYPE html>
<html>
<head>
<title>NodeJS Starter Application</title>
<meta charset="utf-8">
<!--ここから追加-->
<script src="https://code.jquery.com/jquery-1.11.3.min.js"></script>
<script type="text/javascript" src="js/ui_table.js"></script>
<!--ここまで追加-->
</head>
<body>
<!--ここから追加-->
<table id="dataTable" border="1">
<thead>
<tr><th>時間</th><th>項目</th></tr>
</thead>
<tbody id='tableItems'></tbody>
</table><br><br>
<div id="form">
<br>
<button value="全件表示" id="getAll"> 全件表示 </button>
<button value="全件削除" id="removeAll"> 全件削除 </button>
<br><br>
<span>項目名: </span><span><input type="text" id="item1"></span><br>
<button value="追加" id="add">追加</button>
</div>
<!--ここまで追加-->
</body>
</html>
[public] [js] フォルダの下にブラウザ側 JavaScript として作成した、「ui_table.js」は以下のように、$.ajax のサーバー呼び出しに、追加の「/add」、全件表示の「/getAll」、全件削除の「/removeAll」 の3つの機能を追加しました。
いずれも、画面上部の表 「#tableItems」 に結果を表示するようになっています。
// ui_table.js ブラウザUI用 JavaScript (index.htmlより呼ばれる)
$(function(){
console.log('ui_item.js in');
// サーバから取得したデータを、htmlテーブルに追加
var showTable = function(data) {
$("#tableItems").append("<tr></tr>")
.find("tr:last")
.append("<td>" + data.date + "</td>")
.append("<td>" + data.item1 + "</td>")
};
// 追加ボタン(index.htmlのid=add)押下時 実行
$("#add").click(function(e){ e.preventDefault();
var param = {};
param.item1 = $("#item1").val() || "";
// POSTでのajaxコールで、サーバーのapp.jsのapp.post /add呼び出し
$.ajax({
type: 'POST',
data: JSON.stringify(param),
contentType: 'application/json',
url: '/',
success: function(data) {
console.log('success add: ' + JSON.stringify(data));
showTable(data);
},
error: function(data) { console.log('error add: ' + JSON.stringify(data)); }
});
// 入力項目名を空白に
$("#item1").val('');
});
// 全件表示ボタン(index.htmlのid=getAll)押下時 実行
$("#getAll").click(function(e){ e.preventDefault();
$("#tableItems").empty();
// POSTでのajaxコールで、サーバーのapp.jsのapp.post /getAll呼び出し
$.ajax({
type: 'POST',
data: {},
contentType: 'application/json',
url: '/getAll',
success: function(rows) {
for(var i=0; i<rows.length; i++) {
console.log(' row '+ i +": "+ JSON.stringify(rows[i]));
showTable(rows[i].value);
}
},
error: function(data) { console.log('error getAll: ' + JSON.stringify(data)); }
});
});
// 全件削除ボタン(index.htmlのid=removeAll)押下時 実行
$("#removeAll").click(function(e){ e.preventDefault();
// POSTでのajaxコールで、サーバーのapp.jsのapp.post呼び出し
$.ajax({
type: 'POST',
data: {},
contentType: 'application/json',
url: '/removeAll',
success: function(data) { console.log('success removeAll'); },
error: function(data) { console.log('error getAll: ' + JSON.stringify(data)); }
});
$("#tableItems").empty();
});
});
稼動確認
一通りのコードが完成しましたので、以下の「デプロイ」ボタン をクリックして、サーバーで稼動させます。
次に 「アプリケーションを開く」 ボタン をクリックして、Web画面を表示してください。以下の画面が開きますので、項目名に文字を入れて追加すると、Node.js の app.js にアクセスし日時を取得した上で、以下のように上の表に動的に追加されます。
全件を表示し直したり、全件のデータを削除するボタンも使えます。
⇒次は、Eclipseと連携して Bluemix開発する方法