オフラインデータをオンラインに同期できる「PouchDB」でEvernoteの卵的なものを作ってみた。


![pouchdb.png](https://qiita-image-store.s3.amazonaws.com/0/1418/0731398e-286c-6328-3499-acddcd3ba576.png "pouchdb.png")

##1. PouchDBの概要
「PouchDB」は、ドキュメント指向データベース「Apache CouchDB」に触発されて開発されたオープンソースのデータベース。PouchDBを利用すると、オフライン時はローカルにデータを保存し、オンラインに戻ったタイミングでクライアント間でデータを同期するため、アプリケーションのユーザーは利用環境を気にすることなく最新のデータにアクセス可能となる。CouchDBと互換性のあるデータベースに対応している。
![offline_replication.gif](https://qiita-image-store.s3.amazonaws.com/0/1418/dc990ea9-049e-ab13-d7f6-ea35d7c3d902.gif "offline_replication.gif")

##2. remoteサーバーにCouchDBをインストールする

```terminal
brew install couchdb
npm install -g pouchdb-server
```

##3. remoteサーバーを立ち上げる

```terminal
pouchdb-server --port 5984
```

ブラウザで「[http://localhost:5984](http://localhost:5984)」にアクセスして
{"express-pouchdb":"Welcome!","version":"0.10.0"}
が表示されてたら無事サーバーは立ち上がっている。

##4. CouchDBに直接replicateできるようにするためにcorsをインストール

```terminal
npm install -g add-cors-to-couchdb
add-cors-to-couchdb
#もしlocalhostじゃないサーバーをしている場合
#add-cors-to-couchdb #{your-serevr-root-url} -u myusername -p mypassword
```

##5. 実際に利用してみる

__1. pouchdbのjsをダウンロード__
[pouchdbのダウンロードはこちらから](https://github.com/daleharvey/pouchdb/releases/download/3.2.0/pouchdb-3.2.0.min.js)

__2. indexedDBとremoteServerでレプリケーションしてみる__

htmlファイルにこう書いて〜、

```index.html
<script src="pouchdb-3.2.0.min.js"></script>
<script src="app.js"></script>
<h1>Home#index</h1>                                                                                        
<p>Find me in app/views/home/index.html.erb</p>
<div id="display_stored_data"></div>
<div id="display_localdb"></div>
<%= link_to "get local memo", "javascript:void(0);", class: "getLocalData" %>
<div id="display_remotedb"></div>
<%= link_to "get remote memo", "javascript:void(0);", class: "getRemoteData" %><br>
<%= link_to "show all local memo", "javascript:void(0);", class: "showAllLocalData" %><br>
<ul id="show_all_local_memo"></ul>
<%= link_to "show all remote memo", "javascript:void(0);", class: "showAllRemoteData" %>
<ul id="show_all_remote_memo"></ul>
<%= link_to "sync to remote", "javascript:void(0);", class: "syncDataToRemote" %><br>
<%= link_to "delete local memo", "javascript:void(0);", class: "deleteAllLocalData" %><br>
<%= link_to "delete remote memo", "javascript:void(0);", class: "deleteAllRemoteData" %>
```

jsファイルにこう書いて〜、

```app.js
$(function(){
  var user_id = 1;                                                                                         
  var db_name = "documents";
  var remote_db_name = "http://127.0.0.1:5984/documents";
  //PouchDB.debug.enable('*');
  var ts = new Date().getTime().toString();
  var doc = {
    "_id": ts,
    "user_id": user_id,
    "title": "test document title" + new Date().getTime(),
    "body": "test document body" + new Date().getTime()
  };

  PouchDB.destroy(db_name).then(function () {
    return new PouchDB(db_name);
  }).then(function (db) {
    //
    // IMPORTANT CODE STARTS HERE
    //
    db.put(doc).then(function () {
      return db.get(ts);
    }).then(function (doc) {
      document.getElementById('display_stored_data').innerHTML = 'We stored a memo: ' + JSON.stringify(doc);
    });
    var remote_db = new PouchDB(remote_db_name);
    //db.replicate.to(remote_db);
    //db.replicate.from(remote_db);
  });
  //remoteサーバーからデータを取得する
  $(document).on("click",".getRemoteData",function(){
    var remote_db = new PouchDB(remote_db_name);
    remote_db.get(ts,[],function(err, data){
      document.getElementById('display_remotedb').innerHTML = 'We get a remote memo: ' + JSON.stringify(data);
    });
  });

  //indexedDBからデータを取得する
  $(document).on("click",".getLocalData",function(){
    var local_db = new PouchDB(db_name);
    local_db.get(ts,[],function(err, data){
      document.getElementById('display_localdb').innerHTML = 'We get a local memo: ' + JSON.stringify(data);
    });
  });
    
  //remoteサーバーからデータを全データを取得する
  $(document).on("click",".showAllRemoteData",function(){
    var target = document.getElementById('show_all_remote_memo');
    target.innerHTML = "";
    var remote_db = new PouchDB(remote_db_name);
    remote_db.allDocs({include_docs: true}, function(err, doc) {
      doc.rows.forEach(function(row){
        var content = document.createElement("li");
        content.innerHTML =("<p>user:"+row.doc.user_id+" > "+row.doc.title+"</p><span>"+row.doc.body+"</span>");
        target.appendChild(content);
      });
    });
  });
    
  //indexedDBからデータを全データを取得する
  $(document).on("click",".showAllLocalData",function(){
    var target = document.getElementById('show_all_local_memo');
    target.innerHTML = "";
    var db = new PouchDB(db_name);
    db.allDocs({include_docs: true}, function(err, doc) {
      doc.rows.forEach(function(row){
        var content = document.createElement("li");
        content.innerHTML =("<p>user:"+row.doc.user_id+" > "+row.doc.title+"</p><span>"+row.doc.body+"</span>");
        target.appendChild(content);
      });
    });
  });
  
  $(document).on("click",".deleteAllLocalData",function(){
    var db = new PouchDB(db_name);
    db.destroy();
  });
  
  $(document).on("click",".deleteAllRemoteData",function(){
    var remote_db = new PouchDB(remote_db_name);
    remote_db.destroy();
  });
      
  $(document).on("click",".syncDataToRemote",function(){
    var local_db = new PouchDB(db_name);
    var remote_db = new PouchDB(remote_db_name);
    local_db.replicate.to(remote_db);
  });
});
```

__3. 実践！__

1. pageを読み込むと、

 ![Screen Shot 2014-12-24 at 6.41.03 PM.png](https://qiita-image-store.s3.amazonaws.com/0/1418/8d02f358-07f7-a515-f738-334f1bcc53c8.png "Screen Shot 2014-12-24 at 6.41.03 PM.png")

2. 「show all local memo」をクリックするとローカルDBのデータが取得できる

![Screen Shot 2014-12-24 at 6.43.01 PM.png](https://qiita-image-store.s3.amazonaws.com/0/1418/e2884ab2-8ade-8ceb-e4cc-7a1be3426c1e.png "Screen Shot 2014-12-24 at 6.43.01 PM.png")

3. 「show all remote memo」をクリックするとremoteサーバーのデータが取得できる

ただ、まだlocalのデータをremoteにsyncしてないので、表示されない。
![Screen Shot 2014-12-24 at 6.43.01 PM.png](https://qiita-image-store.s3.amazonaws.com/0/1418/e2884ab2-8ade-8ceb-e4cc-7a1be3426c1e.png "Screen Shot 2014-12-24 at 6.43.01 PM.png")

4. 「sync to remote」をクリックしてから「show all remote memo」をクリック

![Screen Shot 2014-12-24 at 6.53.16 PM.png](https://qiita-image-store.s3.amazonaws.com/0/1418/b817e362-20e1-db0b-e828-96c43c9e29aa.png "Screen Shot 2014-12-24 at 6.53.16 PM.png")

きたきた。

5. pageをreloadして、localとremoteの両方のデータを見てみる

![Screen Shot 2014-12-24 at 6.54.26 PM.png](https://qiita-image-store.s3.amazonaws.com/0/1418/d42c6aea-41c4-b794-3426-ab9cace00ea0.png "Screen Shot 2014-12-24 at 6.54.26 PM.png")

6. 再度「sync to remote」をクリックしてから「show all remote memo」をクリックすると、

![Screen Shot 2014-12-24 at 6.55.52 PM.png](https://qiita-image-store.s3.amazonaws.com/0/1418/32f2c9bc-9f37-126b-0537-d55131791b9c.png "Screen Shot 2014-12-24 at 6.55.52 PM.png")

remoteには２つ目のレコードもsyncされましたね。


##6. まとめ

今回はpageのロードでデータをlocalにテストデータを保存して、クリックでsyncしましたが、todoやnote系のアプリだったら、ちゃんとフォームを作って保存ボタンでlocalに保存して、ネットに繋がっていたらサーバーに同期して、いなかったらlocalに保存したままにしておくとかすれば、簡単なevernote的なアプリを作れますね。