まだプログラマーですが何か?

プログラマーネタとアスリートネタ中心。たまに作成したウェブサービス関連の話も http://twitter.com/dotnsf

タグ:ibm

以前に Linux 版 Db2 を導入した時の手順を紹介したブログがありました:
http://dotnsf.blog.jp/archives/2960284.html


3年以上前のこの時の仮想環境が奇跡的に残っていたので久しぶりに使ってみました。で、折角の Db2 コマンドライン環境(?)なので、このコマンドラインインターフェースから IBM Cloud 上の DBaaS である Db2 に接続して使ってみました。以下、その手順の紹介です。

まずは IBM Cloud にログインして Db2 インスタンスを作成します。無料のライトアカウントでも使えるサービスが用意されているので、派手に使わない限りは無料で試すこともできます:
2018052302


無料のライトプランを使う場合はデプロイ先ロケーションを「米国南部」に設定します。加えて自分のメールアドレスを指定します:
2018052303


デプロイ先ロケーションが米国南部の場合、無料の Lite プランが選択可能になります(もちろん他のプランでも構いません)。プラン設定後に「作成」ボタンでインスタンスが作成されます:
2018052304



インスタンス作成後、「サービス資格情報」メニューから「資格情報の表示」を選択します(「資格情報の表示」が存在しない場合は、最初に「新規資格情報」をクリックして作成し、その後に改めて「資格情報の表示」を選択します)。すると画面下部に JSON フォーマットで接続先サーバー名やユーザー、パスワードといった情報を確認できます:
2018052301


この中で、今回使うのは以下の5つの情報です:
 - hostname(接続先のサーバー名)
 - password(接続時のパスワード)
 - port(接続先のポート番号)
 - db(データベース名)
 - username(接続時のユーザー名)


以下では、これら5つの値がこのような内容になっていたと仮定して説明を続けます:
{
  "hostname": "dashdb-txn-sbox-yp-dal09-03.services.dal.bluemix.net",
  "password": "xxxxxxxx",
  "port": 50000,
  "db": "BLUDB",
  "username": "lrz77612",
    :
}



ではこの DBaaS 上のデータベース(BLUDB)にコマンドラインから接続するための手順を紹介します。


db2inst1 ユーザーへの変更

ここから下のコマンドはすべて db2 インストール時に指定したユーザー(今回の例では db2inst1)に切り替えて行う必要があります。というわけでターミナル上でのユーザーを切り替えます:
$ su - db2inst1

ノードカタログの確認

接続先となる Db2 サーバーはサーバーノードとしてカタログに記録されている必要があります。というわけで、まず現在のノードカタログを確認します(青字は出力結果):
$ db2 list node directory
SQL1037W  The node directory is empty.  SQLSTATE=01606

この出力結果によるとノードカタログは空で何も登録されていないようです。


ノードのカタログ登録

というわけで今回の接続先となる IBM Cloud 上の Db2 サーバーをカタログに登録します。以下のように接続先のサーバー名とポート番号を指定し、今回は "dashdb" という名前でカタログに登録しています(太字部分は各自の環境や希望に併せて変更してください):
$ db2 catalog tcpip node dashdb remote dashdb-txn-sbox-yp-dal09-03.services.dal.bluemix.net server 50000
DB20000I  The CATALOG TCPIP NODE command completed successfully.
DB21056W  Directory changes may not be effective until the directory cache is
refreshed.
成功したようです。この状態で再度ノードカタログを確認すると、今度は dashdb という名前のカタログが確認できるはずです:
$ db2 list node directory

 Node Directory

 Number of entries in the directory = 1

Node 1 entry:

 Node name                      = DASHDB
 Comment                        =
 Directory entry type           = LOCAL
 Protocol                       = TCPIP
 Hostname                       = dashdb-txn-sbox-yp-dal09-03.services.dal.bluemix.net
 Service name                   = 50000



ノードカタログを削除

今回は作業しませんが、登録したカタログを削除する場合はカタログ名を指定して以下のように実行します:
$ db2 uncatalog node dashdb


エイリアスの確認

DB2 でデータベースに接続するにはデータベースをエイリアスとして登録する必要があります。というわけで次に接続先となるリモートデータベースのエイリアスを作成します。まずは現在登録されているエイリアスの一覧を確認します:
$ db2 list db directory

 System Database Directory

 Number of entries in the directory = 2

Database 1 entry:

 Database alias                       = JSONDB
 Database name                        = JSONDB
 Local database directory             = /home/db2inst1
 Database release level               = 14.00
 Comment                              =
 Directory entry type                 = Indirect
 Catalog database partition number    = 0
 Alternate server hostname            =
 Alternate server port number         =

Database 2 entry:

 Database alias                       = MYDB
 Database name                        = MYDB
 Local database directory             = /home/db2inst1
 Database release level               = 14.00
 Comment                              =
 Directory entry type                 = Indirect
 Catalog database partition number    = 0
 Alternate server hostname            =
 Alternate server port number         =


この例では(いずれもローカルサーバー内の)JSONDB と MYDB という2つのデータベースエイリアスが登録されていました。この例ではリモートサーバーのエイリアスは登録されていません。


エイリアスの登録

では先程作成した dashdb ノード上の接続先データベース(BLUDB)を "remotedb" という名前でエイリアス登録します:
$ db2 catalog database BLUDB as remotedb at node dashdb
DB20000I  The CATALOG DATABASE command completed successfully.
DB21056W  Directory changes may not be effective until the directory cache is
refreshed.

成功したようです。念の為もう1回エイリアス一覧を確認します:
$ db2 list db directory

 System Database Directory

 Number of entries in the directory = 3

Database 1 entry:

 Database alias                       = REMOTEDB
 Database name                        = BLUDB
 Node name                            = DASHDB
 Database release level               = 14.00
 Comment                              =
 Directory entry type                 = Remote
 Catalog database partition number    = -1
 Alternate server hostname            =
 Alternate server port number         =

Database 2 entry:

 Database alias                       = JSONDB
 Database name                        = JSONDB
 Local database directory             = /home/db2inst1
 Database release level               = 14.00
 Comment                              =
 Directory entry type                 = Indirect
 Catalog database partition number    = 0
 Alternate server hostname            =
 Alternate server port number         =

Database 3 entry:

 Database alias                       = MYDB
 Database name                        = MYDB
 Local database directory             = /home/db2inst1
 Database release level               = 14.00
 Comment                              =
 Directory entry type                 = Indirect
 Catalog database partition number    = 0
 Alternate server hostname            =
 Alternate server port number         =


エイリアスが2つから3つに増え、REMOTEDB が新たに登録されました。


エイリアスを削除

この作業も今回は不要ですが、登録したエイリアスを削除する場合はエイリアス名を指定して次のように実行します:
$ db2 uncatalog db remotedb


エイリアスを指定して接続

では改めてエイリアスを作ったデータベースに接続します。接続時にはユーザー名とパスワードが必要になるので、以下のように指定します:
$ db2 connect to remotedb user lrz77612 using xxxxxxxx

   Database Connection Information

 Database server        = DB2/LINUXX8664 11.1.2.2
 SQL authorization ID   = LRZ77612
 Local database alias   = REMOTEDB

IBM Cloud 上のデータベースに接続できました。後はこのリモートデータベースに対して各種 SQL を実行してテーブルやデータの作成/更新/削除/検索といったコマンドが実行できます。


接続しているエイリアスから切断

なお、接続しているエイリアスから切断する場合は以下のコマンドを実行します:
$ db2 terminate




IBM Cloud から提供されている IoT サービスである IBM Watson IoT Platform (の QuickStart)にメッセージをパブリッシュする Node.js のサンプルアプリケーション(とソースコード)を作って公開しました:
https://github.com/dotnsf/mqtt_pub_ibmiot

2018051501


主要なソースコードは app.js だけですが、内部的に MQTT.js ライブラリを使っています:
2018051500


主な挙動としては settings.js で指定された内容に併せて、1秒(デフォルト)ごとに0から1つずつ増えるカウンタ値、タイムスタンプ値、実行したマシンの CPU 稼働率、12回周期のサイン値およびコサイン値、そしてランダムな値が JSON で IBM Watson IoT Platform の QuickStart に送られます。その際のデバイス ID 値は settings.js 内で指定されていればその値が、されていなければ動的に生成されるようにしました。


IBM Cloud 環境で Node-RED ランタイムを作ると動作を確認しやすく、またそのためカスタマイズの勘所が分かりやすいと思っています。以下、この環境での動作確認方法を紹介します。

まずはこのサンプルを動かす前提として Node.js がインストールされたマシンが必要です。Windows/MacOS/Linux/Raspberry Pi などなど、Node.js をインストール可能なマシンで導入を済ませていると仮定して以下を続けます。

次に上記リポジトリから git clone またはダウンロード&展開して、アプリケーションのソースコードを手元に用意します:
$ git clone https://github.com/dotnsf/mqtt_pub_ibmiot
$ cd mqtt_pub_ibmiot

必要に応じてテキストエディタで settings.js の中身を編集します。とはいえ、変える必要がありそうなのは exports.interval の値(メッセージデータを送信する時間間隔(ミリ秒)。デフォルト値は 1000 なので1秒ごとにメッセージを送信する)と、exports.deviceId の値(後で指定するデバイス ID。デフォルトは空文字列なので、後で自動生成された値になります)くらいです。なお、settings.js の値は変えなくても動きます。


※もし exports.deviceId の値を編集する場合は、("test" のような簡単な単語ではなく)他の人が使わないようなユニークな値になるよう指定してください。exports.deviceId の値をデフォルトのから文字列のままにする場合は、実行時ごとにデバイス ID を生成するので、この値は実行ごとに変わることに留意してください。


ではアプリケーションの動作に必要なライブラリをインストールします:
$ npm install

そして実行します:
$ node app

実行が成功して IBM Watson IoT Platform に接続すると、"client#connect: " という文字列に続いてデバイス ID が画面に表示されます(以下の例では 5d7436e992d0)。この値は settings.js で指定した場合はその値が、指定しなかった場合は自動生成された値が表示されます。この後で使うのでメモしておきます:
2018051502


※なお、メッセージを送信しているアプリケーションの終了方法は特に用意していないので、終了する場合は Ctrl+C で強制終了してください。


これでサンプルアプリケーションが IBM Watson IoT Platform に接続し、exports.interval で指定した値の間隔でメッセージデータを送信し続けている状態になりました。

最後にこの送信データを Node-RED で確認してみます。IBM Cloud で Node-RED ランタイムを作成し、IBM IoT のインプットノード(右側にジョイントのあるノード)と、debug アウトプットノードをキャンバスに配置して接続します:
2018051503


↑IBM Watson IoT Platform サーバーにメッセージが送られてきたらその payload の内容をデバッグタブに表示する、というシンプルなフローです。


IBM IoT インプットノードをダブルクリックし、Authentication が Quickstart になっていることを確認した上で、Device Id 欄に先程確認した実行中アプリケーションのデバイス ID を指定します。そして「完了」してから、このアプリケーションを「デプロイ」します:
2018051504


すると、Node-RED 画面右のデバッグタブに(デフォルトであれば)1秒おきにメッセージが追加されていく様子が確認できるはずです:
2018051505


メッセージの1つを選んで展開してみると、元のアプリケーションから送信されたカウント値(count)、タイムスタンプ値(timestamp)、CPU稼働率(cpu)、サイン値(sin)、コサイン値(cos)、そして乱数値(random)が確認できます。つまり Node.js を使って動かしたアプリケーションから MQTT 経由で実際にデータが送信されていて、その内容を Node-RED と IBM IoT インプットノードを使って取り出して確認できたことになります:
2018051506


送信データをカスタマイズしたり、別の値を送信したい場合は app.js をカスタマイズして、publish 時に送信する data 変数の中身を変える(必要な値を取得して、この中に JSON で入れる)ということになります。こちらはシンプルなのでなんとなく理解できるんじゃないかな・・・と期待しています。


また Node-RED の場合であれば node-red-dashboard と組み合わせることで、ここで取得した値を簡単にチャート化することもできます。例えば Gauge ノードと Chart ノードを使って CPU 負荷とサインカーブをこんな感じで・・・
2018051600


IBM Watson IoT Platform の Quickstart にデータを送信するサンプルとして使ってくださいませ。

IBM Cloud から提供されているコグニティブエンジン IBM Watson を使って、
 1. MNIST の手書き数字サンプルデータを学習させて、
 2. 実際に手書き数字データを送信して、認識させる
という、「学習」と「問い合わせ」のコグニティブエンジン一連の作業を再現させてみます(した)。


今回紹介する一連の作業では、IBM Cloud の以下のサービスを連動させて使います:
 ・IBM Watson Studio
 ・IBM Machine Learning
 ・IBM Cloud Storage
 ・SDK for Node.js ランタイム(上記2のサンプルをクラウド上で稼働させる場合)

以下で紹介する手順は IBM Cloud の無料版であるライトアカウントを使っても同様に動かすことができるようにしているので、興味ある方は是非挑戦してみてください。


1. MNIST の手書き数字サンプルデータを学習させる

人工知能とか機械学習とかを勉強していると、そのチュートリアルとして "MNIST" (Modified National Institute of Standards and Technology)を目にする機会があると思っています。機械学習のサンプルとして手書きで描かれた数字の画像データと、そのラベル(何の数字を描いた画像なのか、の答)が大量にサンプルデータとして公開されており、機械学習を説明する際の様々な場面で使われています:
2018050800


今回、この MNIST データを IBM Watson StudioIBM Watson Machine Learning を使って学習させ、かつ問い合わせ用の REST API を用意します。

・・・と、偉そうに書いていますが、この部分の手順については私の尊敬する大先輩・石田剛さんが Qiita 上でわかりやすく紹介していただいています。今回の学習部分についてはこの内容をそっくりそのまま使わせていただくことにします(石田さん、了承ありがとうございます):
Watson Studioのディープラーニング機能(DLaaS)を使ってみた 

2018050801

↑この作業で MNIST の手書き画像を IBM Watson Machine Learning を使って学習させ、その問い合わせ API を REST API で作成する、という所までが完了します。


2. 手書き数字データを送信して、認識させる

マウスやタッチ操作で画面に手書き数字を描き、その内容を 1. の作業で用意した REST API にポストして何の数字と認識するか、を確認できるようなアプリケーションを作成します。

・・・というか、しました(笑):
2018050804


PC またはスマホでこちらのサイトにアクセスすると体験できるようにしています:
https://dotnsf-fingerwrite-mnist.us-east.mybluemix.net/


フロントエンドはもともと以前に「イラツイ」という手描きイラスト付きツイートサービスを作った際のものを丸パク応用し、問い合わせ API を呼び出すバックエンド部分はデプロイしたモデルの Implementation タブ内にある JavaScript の Code Snippets を参考に作りました。この Code Snippents は各種言語のサンプル(アクセストークンを取得してエンドポイントにリクエストするサンプル)が用意されていて、とても便利です:
2018050809


アプリケーションの使い方はマウスまたは指でキャンパス部分に数字を描いて、"fingerwrite" ボタンを押すと、その描いた数字データを上記 1. で作成した REST API を使って識別し、最も可能性が高い、と判断された数値とその確率が表示される、というものです:
2018050805


PC 画面の場合に限りますが、デバッグコンソールを表示した状態で上記を実行すると、可能性が最も高いと思われた結果だけでなく、全ての数値ごとの確率を確認することもできます:
2018050806

↑常に「2」の確率が高くなってる気がする。。原因は学習の調整不足だろうか??それともデータを渡すフロントエンド側??(2018/May/09 ピクセル毎のデータを取り出すロジックに不具合があったので、修正しました)


なお、この 2. のサンプルアプリは Node.js のソースコードを公開しているので、興味ある方は自分でも同様のサイトを作成してみてください:
https://github.com/dotnsf/fingerwrite-mnist

2018050807


このソースコードから動かす場合、事前に settings.js ファイルを編集しておく必要があります:
2018050808


まず上の3つ、 exports.wml_url, exports.wml_username, exports.wml_password の3つの変数の値は 1. で MNIST データを学習した際に使った IBM Watson Machine Learning サービスのサービス資格情報を確認して、その中の url, username, password の値をそれぞれコピー&ペーストしてください(最初の exports.wml_url だけはおそらくデフォルトで url の値になっていると思います。異なっていた場合のみ編集してください):
2018050803


また一番下の exports.ws_endpoint の値は同様に 1. で使った IBM Watson Studio の Web サービスのエンドポイント(学習モデルをデプロイした時に作成した Web サービス画面の Implementation タブから確認できる Scoring End-point の値)をそのまま指定します:
2018050802


ここまでの準備ができた上でアプリケーションを実行します。ローカル環境で動かす場合は普通に npm install して node app で起動します:
$ npm install
$ node app

IBM Cloud (の SDK for Node.js)を使って動かす場合は、cf ツールbx ツールを使って、そのまま cf push で公開されます:
$ cf push (appname)


今回紹介した方法では IBM Watson Studio と IBM Watson Machine Learning を使って画像データを学習させ、その学習結果に対して REST API で問い合わせをする、という機械学習の一連の流れを体験できます。また学習データ(とモデリング)を変更することで、異なる内容の学習をさせる応用もできますし、学習した内容に問い合わせを行う API も自動生成されるので、フロントエンドの開発も非常に楽でした。
 

業務の忙しさを言いわけに、IBM Cloud の新しい情報に疎くなっていました。で「なんか面白そうな API ないかなあ」とカタログを眺めていたら・・・

「金融」カテゴリに、、ん??
2018041901


こっ、これはっ!? もしやシグナイト!?
2018041902


おー、やっぱりシグナイトだ。世界中の株や為替を始めとする色々なマーケット情報を提供するシグナイトの API が IBM Cloud のサードパーティ API としても登録されていたのでした(知りませんでした、何か)。ただこの API はここからそのまま使えるわけではなく、別途アカウント登録が必要なようで、↓ひとつ進んだこのページの "Xignite" と書かれたリンクからアカウント登録に進みます:
2018041903


すると、この↓ページにジャンプします。ほうほう、シグナイト API は本来有料なのですが、IBM Bluemix(Cloud) ユーザー向けに7日間のトライアルが提供されている模様です:
https://market-data.xignite.com/IBM_Marketplace.html

2018041900


で、ここから名前やメールアドレスを指定して登録し、アドレスに届いたメールの内容を使って申請していきます。途中、以下のような画面になり、こんかいのトライアルで利用する API を1つ指定します(どうやらトライアルで利用できるのは一つだけのようで複数指定はできないようでした)。迷いましたが、個人的にも取引経験のある FX 向けの XigniteGlobalCurrencies を選択しました:
42


更に先に進み、アカウントのパスワードを指定してアクティベートします:
33


アクティベートが完了すると登録したアドレスに以下のようなメールが届きます。ここから "token" と書かれたリンクをクリックして、API 用のトークンを確認できます:
18


再びシグナイトのページに移動し、以下の赤枠部分に API 用のトークンが表示されています。API 実行時にこのトークン文字列が必要になります:
52


次にどんな API が提供されているのか調べてみます。シグナイトの API カタログページから今回選択した API(上記例の場合は XigniteGlobalCurrencies)を探し、その "API List" と書かれたボタンをクリックします:
26


すると指定した種類(XigniteGlobalCurrencies)の API 一覧が表示されます。ここでどんな API が存在して、どうすると実行できるのか、実際の実行結果がどんなフォーマットになるのか、といった情報を確認したり、実際に実行したりできます:
2018041904


試しにひとつ使ってみます。左側の API 一覧からリアルタイムレートを参照する GetRealTimeRate を選びます。すると画面右側が GetRealTimeRate 用に切り替わり、ここから各種パラメータを指定して実際に実行することができます(注 実行できるのはログイン時のみ)。以下の例では Request タブで
 Symbol: USDJPY(米ドル円レート)
 Result Format: JSON(結果を JSON で取得)
を指定しました。するとその下の URL が動的に切り替わり、この条件で API を実行する際のエンドポイント URL を示してくれます。下図ではモザイクをかけていますが、この URL にはトークンが含まれているので、そのままコピペ等で実際に確認することも可能な URL になっています。最後に下の "View Result" ボタンを押して実行します:
2018041905


成功すると実行結果が下部に JSON フォーマットで表示されます:
2018041906


実際の中身はこんな感じ、ほぼリアルタイムに値が取得できています(このタイミングで1ドルを買うと 107.374 円、売ると 107.368 円で、仲値が 107.371 円、という結果でした):
{
 "Outcome": "Success",
 "Message": null,
 "Identity": "Request",
 "Delay": 0.0167211,
 "BaseCurrency": "USD",
 "QuoteCurrency": "JPY",
 "Symbol": "USDJPY",
 "Date": "04/19/2018",
 "Time": "9:18:18 AM",
 "QuoteType": "Spot",
 "Bid": 107.368,
 "Mid": 107.371,
 "Ask": 107.374,
 "Spread": 0.006,
 "Text": "1 United States dollar = 107.371 Japanese yen",
 "Source": "SIX Financial Information"
}

トライアルだと7日間限定とはいえ、こんな便利な API が IBM Cloud から利用できるようになっていたんですねー。パラメータを変えて実行したり、他の API もここから同様に試すことができそうです。


なお、トライアルではない正式版(?)の API の価格については Flexible Pricing Model が適用されるようで、価格そのものはウェブからは確認できませんでした。興味ある方はこちらから問い合わせる必要がありそうです:
https://www.xignite.com/Pricing

 

 は IBM CloudantApache CouchDB と API 互換のある NoSQL データベースです。JavaScript で操作することができます。npm を使ってサーバーサイドで動かすこともできますが、ブラウザから JavaScript ライブラリをロードして、個々のブラウザ内で使うことも可能です。

特にこれをブラウザから使う場合、マスターデータはクラウドの IBM Cloudant で保持しつつ、必要なデータをユーザーのブラウザと同期して、ほぼすべての処理をローカルブラウザ内で完結させる(=時間のかかるDBアクセスをローカルDBだけを対象に行えばよくなるので、アプリケーションとしての安定性やパフォーマンス向上も期待できる)、ということが可能になります。とても強力な同期機能を持ったデータベースエンジンと言えます。
2018040900


この「同期」を具体的にどうやるか、という内容が今回のブログエントリです。


今回の説明では、サーバー側の DB を IBM Cloudant で用意することにします。IBM Cloud のライトアカウントを作成すると容量 1GB まで使えるライトプランの DBaaS が無料で用意できます。

で、この Cloudant DB をブラウザに同期・・・するわけですが、IBM Cloudant を使う場合はその前に1つ設定が必要です。標準状態の IBM Cloudant はクロスオリジンからのアクセスを許可していません。そのため、標準設定のままウェブブラウザから同期をとろうとするとクロスオリジンアクセスになってしまい、エラーとなってしまいます。したがってクロスオリジンアクセスを許可するよう、設定を変更する必要があります。詳しくはこちらにも記載していますが、curl コマンドと IBM Cloudant の API を使って IBM Cloudant の CORS アクセスを有効にするための設定を行います:
$ curl -i -u 'db_username:db_password' -XPUT 'https://db_username.cloudant.com/_api/v2/user/config/cors' -H 'Content-type: application/json' -d '{"enable_cors":true,"allow_credentials":true,"origins":["*"]}'

↑db_username, db_password は IBM Cloudant のインスタンスにアクセスするためのユーザー名およびパスワードです。


次にブラウザ内の JavaScript で DB の同期を行います。普通に「データベースそのものの同期をとる」のであれば話は単純で、以下のようなコードを記述するだけです:
  :
  :
<html>
<head>
<script src="https://cdn.jsdelivr.net/pouchdb/5.4.5/pouchdb.min.js"></script>
<script>
var localDB = new PouchDB( 'testdb' );
var remoteDB = new PouchDB( 'https://db_username:db_password@db_username.cloudant.com/testdb' );

remoteDB.sync( localDB, {
live: true, retry: true });
: :

まず CDN を指定して PouchDB のライブラリをロードします。そして IBM Cloudant のユーザー名(db_username)とパスワード(db_password)を指定して、'testdb' という名前のデータベースインスタンスを remoteDB 変数に代入します。これで IBM Cloudant 上のリモートデータベースを remoteDB から操作できるようになりました。同時にローカルブラウザ内に(同じ名前の)'testdb' という名前のデータベースインスタンスを作って localDB 変数に代入しています(こちらは作成時点では空です)。 この2つのリモート/ローカルデータベースを sync() 関数で同期するように指定しています。これによってこれら2つのデータベースインスタンス変数の内容は自動同期され、一方(例えばブラウザ内の localDB)に変化が起こるともう一方(サーバーの remoteDB)にその変化内容が勝手に反映される、という仕組みが実現できます。

ちなみに sync() 実行時の live:true オプションはリアルタイム同期の指定で、retry:true オプションは一度接続が切れた後に自動的にリトライして接続が戻った時に同期も復活させるための指定です。ここまでは超簡単です。


さて、本来やりたかったのはデータベースをまるごと同期するのではなく、データベースの一部だけを同期する、というものです。上記例だと remoteDB はサーバー側のものなので、全部で数ギガバイトになったりそれ以上になったりすることも想定しないといけないのですが、localDB はブラウザ内で作るものなのであまり大きくなっては困ります。そこで(一般的には部分同期とか Partial Sync とか呼ばれる方法で)特定条件を満たす一部の文書だけを対象にローカルに同期し、ローカルでの変更・追加・削除といった処理をサーバー側のマスターに同期し直す方法を紹介します。

PouchDB にも部分同期機能は存在しています。ただそこで「この条件を満たす文書だけ」を指定する方法がかなり限られていて、現時点では文書 ID を配列で指定する方法しかないように見えます(このフィールドがこの値で・・・みたいなクエリーではできないっぽい)。具体的にはこんな感じ:
  :
  :
<html>
<head>
<script src="https://cdn.jsdelivr.net/pouchdb/5.4.5/pouchdb.min.js"></script>
<script>
var localDB = new PouchDB( 'testdb' );
var remoteDB = new PouchDB( 'https://db_username:db_password@db_username.cloudant.com/testdb' );

var doc_ids = [ 'xxx', 'yyy', 'zzz' ];  //. 同期対象文書の _id 値配列

remoteDB.sync( localDB, {
doc_ids: doc_ids,
live: true, retry: true }); : :

上記例では 'xxx', 'yyy', 'zzz' という3つの文書ID(Cloudant 内だと文書の _id の値)を指定して、sync() 関数を doc_ids パラメータで配列指定しています。これだけで localDB には指定された3文書だけが同期され、削除を含めた変更があるとリモートにも即時に反映されるようになります。

したがって実装する場合はページロード時の最初に IBM Cloudant に対してクエリー API を実行して同期の対象となる文書(の ID 配列)をまとめて取得し、その ID 配列を指定して PouchDB と部分同期する、という流れになると思っています。この方法なら最初のロード時のネットワーク接続は必須になりますが、どのみちページをロードするにもネットワークは必須だし、同期をとった後はネットワークが切れても平気、というシステム構成が可能になります。


なお、一点だけ注意が必要なことがあります。この方法で部分同期した後に localDB に新たに文書を追加した場合です。部分同期の条件は doc_ids に指定された文書ID配列だったので、ここに含まれない新しい文書を追加してもサーバー側には同期されません。その場合は新たに doc_ids を指定しなおして(新しい文書の ID を追加して)改めて sync() 関数を実行する必要があります:
  :
  :
<html>
<head>
<script src="https://cdn.jsdelivr.net/pouchdb/5.4.5/pouchdb.min.js"></script>
<script>
var localDB = new PouchDB( 'testdb' );
var remoteDB = new PouchDB( 'https://db_username:db_password@db_username.cloudant.com/testdb' );

var doc_ids = [ 'xxx', 'yyy', 'zzz' ];

remoteDB.sync( localDB, {
doc_ids: doc_ids, live: true, retry: true }); : : function add( doc ){ //. ドキュメントを追加する処理 localDB.put( doc ).then( function( res ){ //. localDB に文書(doc)追加 doc_ids.push( doc._id ); //. 文書の _id 値を配列に追加 remoteDB.sync( localDB, { //. sync() 再実行 doc_ids: doc_ids, live: true, retry: true }); }).catch( function( err ){ console.log( err ); }); }

例えば上記例では add( doc ) 関数の中で doc に指定されたオブジェクトを localDB に追加する想定で処理を記述していますが、localDB.put() が成功したら doc_ids 配列を更新した上で remoteDB.sync() を再実行して同期条件を変えるようにしています。

現実問題としては追加なのか更新なのか(どちらも put() 関数を使う)、更新だとすると _rev の値も必要になって・・・とか、多少細かい実装が必要になることも事実ですが、一応これだけでローカルDBとその部分同期を使ったアプリの実装はできることになります。

問題は上述したローカルDBに同期したい文書の ID をどうやって調べるかですが、そこはやっぱり一度サーバーにクエリー投げるしかないのかなあ・・・


なお、PouchDB の API Reference はこちらを参照ください:
https://pouchdb.com/api.html


このページのトップヘ