モバイル機器でもデスクトップ機器でも使用できるオフライン Web アプリケーションを CouchDB を使って作成する

モバイル・アプリケーションで最大の難題の 1 つはデータの同期です。この問題に対する興味深いソリューションとして、NoSQL データベースの CouchDB を使用する方法があります。CouchDB はドキュメント指向のデータベースであり、SQL データベースに代わりうるものです。CouchDB を使用すると、モバイル機器でクラウド機能を使用することができ、ローカルにデプロイされたアプリケーションでローカルのデータ・ストレージを使ってオフラインで作業した後、再度オンライン接続されたときにクラウドの他の部分とデータを共有することができます。この記事では、サンプル・アプリケーションを作成してデプロイするなかで CouchDB が持つさまざまな概念について学びます。

Dietmar Krueger, IT Architect, IBM

Photo of Dietmar KruegerDietmar Krueger は、IBM Global Business Services のサービス・シリーズの 1 つである Application Innovation Services に従事しています。彼はオブジェクト指向ソフトウェアの開発を 17 年にわたって行ってきており、アジャイル・ソフトウェア開発、軽量アーキテクチャー、動的型付けプログラミング言語に情熱を注いでいます。



2010年 12月 21日

はじめに

HTML5 ブラウザーに組み込まれているような、分散型データベースを対象とした SQL による同期メカニズムを利用するには、複雑な作業が必要になります。一方、Apache CouchDB には同期機能が最初から組み込まれています。(CouchDB の同期機能については「参考文献」を参照)。この記事では CouchDB が持つさまざまな概念と技術的な詳細について、典型的な使用事例を使って説明します。使用事例として、単純な在庫管理アプリケーションのプロトタイプを作成してデプロイします。

この在庫管理アプリケーションと同様のアプリケーションに HTML5 のさまざまな概念を適用したものを以前私が developerWorks に寄稿した記事「モバイル機器用のオフライン Web アプリケーションを HTML5 を使って作成する」で紹介しましたが、そこでは同期については触れませんでした。今回、私はこの記事のために、そのアプリケーションをマイグレーションして CouchDB 環境のストレージ機能および標準的な同期機能を使えるようにしました。この記事で使用するソース・コードは下記の「ダウンロード」セクションからダウンロードすることができます。

概要

図 1 には、CouchDB のサンプル・アプリケーションのアーキテクチャーを構成する主要コンポーネントの概観図を示してあります。以前の記事で紹介した HTML5/SQL ソリューションも同様のコンポーネントで構成されています。どちらのソリューションにも、HTML、JavaScript、ローカル・データ・ストレージ、リモート・データ・ストレージが含まれています。

図 1. オフライン CouchDB アプリケーションの中核要素
この図にはオフライン CouchDB アプリケーションの中核要素として、ローカル要素とリモート要素の両方が示されています。これらの要素については、以下の文で説明しています。
HTML ページ
HTML5 アプリケーションと CouchDB アプリケーションの中核です。モデルの役割を持つ HTML ページには、表示されるデータと (デフォルトの) 描画情報が含まれています。ページの HTML 要素は、HTML の DOM (Document Object Model) ツリーの階層構造に従って構成されています。

ユーザーによってイベントが起動されると、通常のリクエスト/レスポンス・サイクルが実行されてページがロードされ、そのページに関連付けられた JavaScript 関数が実行されます。注目すべき点として、これらのアプリケーションは 1 つの HTML ページで構成されており、リクエスト/レスポンス・サイクルによって他の HTML ページをロードする必要はありません。すべてのアクションは 1 つのページ上で実行されます。

JavaScript
HTML5 アプリケーションと CouchDB アプリケーションのコントローラー機能が含まれています。HTML 要素はイベント・ハンドラーによって JavaScript 関数にバインドされています。JavaScript からは、アプリケーションのすべてのユーザー・インターフェース要素が含まれる HTML DOM ツリーにアクセスすることができ、データ入力として DOM ツリーを使用することで計算処理を行うことができます。計算処理の結果は HTML ページを変更することでユーザーに表示されます。
ローカル・データ・ストレージ
HTML5 アプリケーションの SQL データベースはスキーマをベースにしており、複数のテーブルを結合することで各テーブルのデータを合成します。CouchDB アプリケーションのデータ・ストレージにはスキーマがありません。文書は JSON 文書として格納され、取得されます。テーブルを結合することによってデータを組み立てる必要はありません。

SQL データベースは SQL クエリーを使ってデータを管理します。CouchDB では RESTful な手法を使います。つまりすべての文書は RESTful なリソースであり、リクエストには HTTP メソッドを使います。

リモート・データ・ストレージ
アプリケーションのインフラストラクチャーは、互いに複製し合うデータ・ストレージ・ノードのネットワークで構成されます。SQL データベースの世界では、複製のための複雑なインフラストラクチャーを作成または管理する必要があります。

NoSQL の CouchDB アーキテクチャーには、デフォルトの複製フレームワークが用意されています。文書が競合した場合、文書のマージを実際に行うのは CouchDB アプリケーションに固有の機能です (「参考文献」を参照)。これは CouchDB の最も強力な機能の 1 つです。

サンプル・アプリケーション

このセクションでは、MyHomeStuff というサンプル・アプリケーションの概要を説明します。このアプリケーションは皆さんが所有している物を記録しておく単純な在庫管理アプリケーションです。このアプリケーションの機能は以前の記事で紹介した HTML5 バージョンのアプリケーションの機能と同じです。図 2 は、このアプリケーションを Windows® 上の Firefox® で実行するときの画面を示しています。

図 2. Windows 上の Firefox に表示された在庫管理システム
在庫管理システムのスクリーンショットが表示されており、Overview セクション、項目を追加するための Details セクション、そして Replicate セクションがあります。以下の文に詳しい説明があります。

このアプリケーションを Android™ 上の Web ブラウザーで実行するときの画面は以下のとおりです。

図 3. Android に表示された在庫管理システム
在庫管理システムのスクリーンショットが表示されており、ブラウザー上に表示されている画面の構成は図 2 と同じですが、図 2 よりも小さな、Android の画面に表示されています。

このアプリケーションにより、自分が所有している物を追跡することができます。画面の上の方にあるリストには、入力されたすべての項目 (本など) の概要が表示されています。このリストの 1 つの項目を選択すると、その項目の詳細 (数量と名称) が画面の中央にあるフォームに表示されます。選択された項目は、「update (更新)」ボタンを使って詳細を変更することや、「delete (削除)」ボタンを使ってアプリケーションから削除することもできます。新しい項目を作成するためには、その項目の数量と名称をフォームに入力し、「create (作成)」ボタンをクリックします。

画面の下の方では、複製プロセスを実行することができます。複製プロセスを実行するには、ソースの URL とターゲットの CouchDB を入力し、「replicate (複製)」ボタンをクリックします。ターゲットの CouchDB は既存のリモート・データベースまたはローカル・データベースです。

HTML の詳細

HTML ページには、宣言、外部 JavaScript ファイルへの参照、そしてこのアプリケーションに欠かせない、基本構造を構成する HTML 要素が含まれています。リスト 1 は HTML コードを示しています。

リスト 1. HTML コード
<!DOCTYPE html>
<html>
  <head>
  	<title>MyHomeStuff2</title>
  	<script src="/_utils/script/jquery.js"></script>
  	<script src="/_utils/script/jquery.couch.js"></script>
  	<script src="script.js"></script>
  </head>
  <body>
  
    <h3>Overview</h3>
    <ul id="itemData" ></ul>

    <h3>Details</h3>
    <form name="itemForm">
        <input type="hidden" name="id" id="idId" />
        <input type="hidden" name="rev" id="revId"/>
        <label for="amount">Qty: </label>
        <input type="text" name="amount" id="amountId" size = 3/>
        <label for="name">Name: </label>
        <input type="text" name="name" id="nameId" size=12 />
        <br><br>
        <input type="button" id="createId" value="create" />
        <input type="button" id="updateId" value="update" />
        <input type="button" id="deleteId" value="delete" />
    </form>
   
    <h3>Replicate</h3>
    <form>
        <label for="sourceDBId">Source: </label>
        <input id="sourceDBId" type="text"></input>
        <br><br>
        <label for="targetDBId">Target: </label>
        <input id="targetDBId" type="text"></input>
        <br><br>
        <input id="replicateId" type="button" value="replicate"></input>
   </form>
   
  </body>
</html>

JavaScript の部分では jQuery ライブラリーが使われているため、HTML ページにはイベント・ハンドラーの属性は含まれていません。(クリック・イベントの) イベント・ハンドラーは JavaScript コードから HTML フォームのアクションにバインドされています。

CouchDB とのやり取りには jquery.couch.js という JavaScript ライブラリーが使われています。jquery.couch.js を使うことで、簡単な JavaScript を作成すれば CouchDB と通信できるようになります。例えば、RESTful な CRUD 操作 (例えば PUT /tutorial/task/4 ... など) のための通信を行うコードを作成する代わりに、db.saveDoc(aTask) を使うことができます。

より高度なアプリケーションを作成するためには、CouchApp フレームワークを使う必要があります。CouchApp は一連のスクリプトで構成されており、これらのスクリプトを使うことで CouchDB アプリケーションを簡単に作成することができます (詳細は、「参考文献」を参照)。

JavaScript の詳細

JavaScript コードは以下の 3 つの主要なブロックで構成されています。

  • 初期化関数
  • DB (CRUD) 操作を行い、ビューを最新の情報で更新する関数
  • 複製関数

最初のブロックにはデータ・ストレージとビューのための初期化コードが含まれています (リスト 2)。

リスト 2. refreshItems 関数が含まれる JavaScript コード
var db = $.couch.db(getCurrentDBName());

function getCurrentDBName() {
    return window.location.pathname.split("/")[1];
}

$(document).ready(function() {
    //1. init stuff
    refreshItems();
    $('#sourceDBId').val(db.name);
    $('#targetDBId').val(db.name + "-copy");
    
    //2. event handler crud stuff
    ...
});

function refreshItems() {
    $("ul#itemData").empty();
      
    db.view("myDesign/myView", {
        success: function(data){
            data.rows.map(function(row) {
            $('ul#itemData').append('<li id="'+row.value._id+'">'
                +row.value.amount
                +" x "
                +row.value.name
                +'</li>');
                     
            $('#'+row.value._id).click(function() {
                $('#idId').val(row.value._id);
                $('#revId').val(row.value._rev);
                $('#amountId').val(row.value.amount);
                $('#nameId').val(row.value.name);
                return false;
            });
            });
        },
        error: function(req, textStatus, errorThrown){alert('Error '+ textStatus);}
        });
}

上記のコードで行っているのは以下の内容です。

  • CouchDB のインスタンスを作成します。データベースの名前は現在の URL から抽出されます。
  • DOM が初期化された後、文書の ready 関数が呼び出されます。ready 関数は最初に refreshItems 関数を呼び出した後、複製フォームのフィールドにソース・データベースの名前とターゲット・データベースの名前が入れられます。
  • refreshItems 関数は、既存のレコードに対するクエリーを実行し、取得したデータを使って HTML ページを構成します。詳細は、以下のとおりです。
    • 古いデータを DOM ツリーから削除します。
    • CouchDB に対してクエリーを実行します。CouchDB に対してクエリーを実行し、レポートを作成するために使われるのは view 関数です。

      クエリーは、成功用のハンドラー関数とエラー用のハンドラー関数によって実行されます。view 関数は HTTP の GET を使って RESTful なクエリーを実行します。ビューはマップ関数で構成され、このマップ関数により、name フィールドとamount フィールドを持つ各文書がキーと値のペアに変換されます。キーは ID であり、値はその文書です (myView というビューのマップ関数については「デプロイメント」セクションを参照)。

    • 成功用のハンドラーはすべての値に対して HTML のリスト要素を作成し、それらのリスト要素がリストに追加されます。また、すべてのリスト要素に対してクリック・イベント・ハンドラーが追加され、クリックへの応答として、選択された内容がフィールドに追加されます。
    • エラー・ハンドラーにより、アラート・ダイアログと共に問題が表示されます。

イベント・ハンドラーは refreshItems 関数の 2 番目のブロックにあります。このブロックには、ボタン・バーに対するイベント・ハンドラーと、updatedeletecreate のリストが含まれています。リスト 3 は update 用のコードを示しています。(create とdelete は update と構造が似ているため、ここには示してありません。このサンプル・アプリケーションのすべてのソース・コードは下記の「ダウンロード」セクションからダウンロードすることができます。)

リスト 3. JavaScript による update の コード
...
    //event handler crud stuff
...
    $('input#updateId').click(function(e) {
         
       if ($('#idId').val().length == 0) {
           return;
       }
       
       var aTask = {
           _id: $('#idId').val(),
           _rev: $('#revId').val(),
           amount: $('#amountId').val(),
           name:$('#nameId').val()
       }
       db.saveDoc(aTask, { success: function(resp) {
           refreshItems();
       }});
    });
...

上記のコードでは以下の処理を行っています。

  • フォームのフィールドの値を読み取り、検証します。
  • 値が有効な場合には、JSON オブジェクトが作成され、HTTP の PUT を使って更新用の呼び出しが行われます。
  • 成功用のハンドラーにより、更新された HTML ページにクエリーの結果が表示されます。

複製関数のコードには内容が凝縮されています (リスト 4)。

リスト 4. 複製用の JavaScript コード
$('#replicateId').click(function() {
    var sourceDB = $('#sourceDBId').val();
    var targetDB = $('#targetDBId').val();
    $.couch.replicate(sourceDB, targetDB, {
        success: function(data){alert('Replication was performed');},
        error: function(req, textStatus, errorThrown){alert('Error '+ textStatus);}
    });
});

上記のコードでは以下の処理を行っています。

  • 複製フォームのフィールドの値を読み取ります。
  • 複製用の呼び出しを実行します。
  • 複製の結果をアラート・ボックスとして表示します (成功用のハンドラーまたはエラー・ハンドラーによってアラート・ボックスが表示されます)。

デプロイメント

読者のコンピューターに CouchDB がインストールされていれば、このサンプル・アプリケーションを実行することができます。CouchDB のインストーラーは、Linux®、Windows、Mac®、Android でそれぞれ異なります (この記事の執筆時点で Android のバージョンは 2.1 またはそれ以降であり、CouchDB の Android ポートは 0.50 アルファ・バージョンであったことに注意してください)。あるいは、ホスティング・サービスを使うこともできます。私は CouchOne の無料のホスティングを使ってみたところ、うまく行きました (「参考文献」を参照)。

CouchDB をインストールできると、ダウンロードされたアプリケーションをコンテナーに入力することができます。以下はそのためのステップです。

  1. アプリケーションとデータ用のデータベースを作成します。
    • Create Database ... (データベースを作成 …)」をクリックします。
    • 「Create New Database (新規データベースを作成)」ダイアログで、「Database Name (データベース名)」フィールドに名前 (例えば、「stuff_db」) を入力し、「Create (作成)」をクリックします。
  2. データを含んだ文書を (テスト用に) 作成します。
    • New Document (新規文書)」 をクリックします。
    • Add Field (フィールドを追加)」をクリックします。
    • 「Field (フィールド)」に「name」と入力し、「Value (値)」に「table」と入力します。

      緑色のチェック・マークまたはタブ・キーを使って内容を承認します。

    • Add Field (フィールドを追加)」をクリックします。
    • 「Field (フィールド)」に「amount」と入力し、「Value (値)」に「3」と入力します。この内容を承認します。
    • Save Document (文書を保存)」をクリックします。

      これでクエリー用の最初のデータの準備ができました。

  3. View (ビュー) を作成し、Design Document (設計文書) として保存します。
    • 「Overview (概要)」 --> 「stuff_db」の順に選択します。
    • (左上にあるプルダウン・リストから)「View: Temporary view... (ビュー: 一時ビュー...)」を選択します。
    • 以下のマップ関数を入力します。
      function(doc) {
        if (doc.name && doc.amount)
        {
          emit(doc._id, doc);
        }}

      データベースの中にある文書のうち、name フィールドと amount フィールドにヌル以外の値を持つ各文書に対し、ビューの中に結果を示す行が作成されます。結果を示す行のキーは文書の ID であり、値は文書そのものです。

    • テストとして、「Run (実行)」をクリックします。その結果として、入力された文書のキーと値のペアが得られます。
    • Save As... (名前を付けて保存)」をクリックします。
    • 「Save View As... (名前を付けてビューを保存...)」ダイアログで、「Design Document (設計文書)」フィールドに「_design/myDesign」と入力し、「View Name (ビューの名前)」フィールドに「myView」と入力し、「Save (保存)」をクリックします。

      これで、CouchDB アプリケーションの保存先となる設計文書が用意できました。

  4. ビューに対するクエリーを実行します。
    • ブラウザーのアドレス・バーに以下の内容を入力します。
      http://127.0.0.1:5984/stuff_db/_design/myDesign/_view/myView
    • 応答として、入力されたデータがブラウザーに表示されます。このデータは以下のようなものです。
      {"total_rows":1,"offset":0,"rows":[
      {"id":"c9938dc172b31a34ef4f0d7f3f000d5d",
      "key":"c9938dc172b31a34ef4f0d7f3f000d5d",
      "value":{"_id":"c9938dc172b31a34ef4f0d7f3f000d5d",
      "_rev":"3-d107f491d254b01c0135fd1e8dd13e0a",
      "table":null,"name":"table","amount":3}}
      ]}

      (見やすくするため、意図的に改行を入れてあります。)

  5. ブラウザーのアドレス・バーに以下の内容を入力し、新しい設計文書を開きます。
    http://127.0.0.1:5984/_utils/document.html?stuff_db/_design/myDesign

    そして、この設計文書に対して添付ファイルをアップロードします (アプリケーションに機能を追加します)。
    • 「File (ファイル)」で「Upload Attachment (添付ファイルをアップロード)」を選択して「index.html」を指定し、「Upload (アップロード)」をクリックします。
    • 「File (ファイル)」で「Upload Attachment (添付ファイルをアップロード)」を選択して「script.js」を指定し、「Upload (アップロード)」をクリックします。
    • Save Document (文書を保存)」をクリックします。
  6. 設計文書の「_attachments」フィールドから「index.html」を値として選択し、以下の内容を指定することでアプリケーションを開きます。
    http://127.0.0.1:5984/stuff_db/_design/myDesign/index.html
  7. アプリケーションに対してデータの入力およびデータの変更を行います。

アプリケーションを正常にインストールできると、以下の複製メカニズムを使って別の CouchDB データベースにアプリケーションをデプロイすることができます。

  1. 単純にするために、同じ CouchDB ノードに新しいデータベースを作成します (例えば new-stuff-db など)。
  2. 既存の CouchDB データベースの URL を入力します。「Source (ソース)」フィールドにソース・データベースの名前 (stuff_db) を入力し、「Target (ターゲット)」フィールドにターゲットの URL (new-stuff-db) を入力します。
  3. replicate (複製)」をクリックします。データとプログラム・コードを含むデータベース全体が複製されます。

    複製データベースに入力された新しいデータを元のデータベースに単純に転送する場合も、同じ方法で簡単に行うことができます。

  4. CouchDB データベースをリモートの CouchDB ノードに複製してみてください。

    例えば、mysubdomain というサブドメインで CouchOne Hosting に登録し、mydatabase というデータベースを作成する場合には、ターゲットの URL として下記を使います。

    http://mysubdomain.couchone.com/mydatabase

まとめ

この記事では、CouchDB を使ったオフライン・アプリケーションについて、技術的な視点から学びました。また単純な在庫管理アプリケーションのプロトタイプを使って、JSON によるストレージ機能と標準的な同期機能を備えた CouchDB の技術について説明しました。


ダウンロード

内容ファイル名サイズ
Source code for this articleOfflineCouchDBAppSrc.zip3KB

参考文献

学ぶために

製品や技術を入手するために

議論するために

コメント

developerWorks: サイン・イン

必須フィールドは(*)で示されます。


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


お客様が developerWorks に初めてサインインすると、お客様のプロフィールが作成されます。会社名を非表示とする選択を行わない限り、プロフィール内の情報(名前、国/地域や会社名)は公開され、投稿するコンテンツと一緒に表示されますが、いつでもこれらの情報を更新できます。

送信されたすべての情報は安全です。

ディスプレイ・ネームを選択してください



developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

必須フィールドは(*)で示されます。

3文字から31文字の範囲で指定し

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


送信されたすべての情報は安全です。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Web development
ArticleID=620282
ArticleTitle=モバイル機器でもデスクトップ機器でも使用できるオフライン Web アプリケーションを CouchDB を使って作成する
publish-date=12212010