FirebaseのRealtime Databaseをざっくり使ってみる ~導入から取得編(保存に関しては編集中)~

Firebaseのざっくりとした概要に関しては[以前書いた記事](http://qiita.com/seiya1121/items/1436fde30752843daa47) もしくは[公式ドキュメント](https://firebase.google.com/docs/database/)からどうぞ

公式ドキュメントのサンプルコードを見ながら、使い方をみてみます

## 準備
実際にアプリに導入する前にやるべきことがいくつかあります。

１. [Firebaseコンソール](https://console.firebase.google.com/)にプロジェクトを立ち上げます。

<img width="817" alt="Screen Shot 2016-12-14 at 0.36.57.png" src="https://qiita-image-store.s3.amazonaws.com/0/39342/4c45939f-ae56-8198-6cca-f284c76ba963.png">

２. 任意のアプリを選択し、諸々キー / 導入をする際に必要なスクリプトを取得します。(今回はウェブアプリを選択)

```js
<script src="https://www.gstatic.com/firebasejs/3.6.3/firebase.js"></script>
<script>
  // Initialize Firebase
  var config = {
    apiKey: <YOUR_API_KEY>,
    authDomain: <YOUR_AUTH_DOMAIN>,
    databaseURL: <YOUR_DATABASE_URL>,
    storageBucket: <YOUR_STRAGE_BUCKET>,
    messagingSenderId: <YOUR_MESSAGIN_SENDER_ID>
  };
  firebase.initializeApp(config);
</script>
```

３. コマンドインターフェイスをインストール
インストールには、npmを要します。

```
npm -g install firebase-tools
firebase version
firebase login
firebase use --add # Firebaseを導入するアプリのディレクトリで実行
```

## 導入
１. Initialize
ことRealtime databaseにだけ言えることではないですが、firebaseを実際にアプリに導入する際に、必ず初期設定をする必要があります。

```js
<script src="https://www.gstatic.com/firebasejs/3.6.3/firebase.js"></script>
<script>
  // Initialize Firebase
  var config = {
    apiKey: <YOUR_API_KEY>,
    authDomain: <YOUR_AUTH_DOMAIN>,
    databaseURL: <YOUR_DATABASE_URL>,
    storageBucket: <YOUR_STRAGE_BUCKET>,
    messagingSenderId: <YOUR_MESSAGIN_SENDER_ID>
  };
  firebase.initializeApp(config); //ここでinitialize
</script>
```

２. database()
initializeしたら実際に、databaseのライブラリを呼びます。

```
firebase.database();
# databaseURL: <YOUR_DATABASE_URL> を参照してくれてます。
```

## 実践
#### 保存(編集中)
以下の4種類のメソッドが用意されています。

| メソッド | 一般的な使用例 |
| :------------ | :------------ |
|set()| users/<user-id>/<username> など、定義済みのパスへのデータの書き込みや、データの置換を行います。|
|push()|データのリストに追加します。push() を呼び出すたびに、user-posts/<user-id>/<unique-post-id> のような一意の ID が生成されます。|
|update()|データのすべてを置換することなく、定義済みのパスのキーの一部を更新します。|
|transaction()|同時更新によって破損する可能性がある複合データを更新します。|

[公式ドキュメント](https://firebase.google.com/docs/database/web/save-data)から抜粋

### 基本的な書き込み
#### set()
基本的な書き込みは`set()`メソッドを使用します。

```js
var commentsRef = firebase.database().ref('comments');
commentsRef.set({ body: "テスト！" });
```

#### push()
> `push()`メソッドを使用すると、該当のコンテンツ追加時に、一意の ID を生成します。
> そうすることで、書き込みの競合を伴わずに複数のクライアントが同時に子を同じ場所に追加できます。
[公式ドキュメント](https://firebase.google.com/docs/database/web/save-data)から抜粋

```js
var commentsRef = firebase.database().ref('comments');
commentsRef.push({ body: "テスト！！！" });
```

#### update()
> 特定の複数のコンテンツに同時に書き込むには、`update()`メソッドを使用します。
> `update()`の呼び出し時に、キーのパスを指定して下位レベルの子の値を更新できます。
[公式ドキュメント](https://firebase.google.com/docs/database/web/save-data)から抜粋

```js
 var updates = {};
  updates['/posts/' + Key] = postData;
  updates['/user-posts/' + uid + '/' + Key] = postData;

  return firebase.database().ref().update(updates);
```

### 取得
データ取得では以下のイベントを利用します。

| イベント | 一般的な使用方法 |
| :------------ | :------------ |
|value| パスのコンテンツ全体に対する変更の読み取りとリッスンを行います。 |
|child_added|アイテムのリストを取得するか、アイテムのリストへの追加がないかリッスンします。 child_changed や child_removed と併用して、リストに対する変更をモニタリングすることをおすすめします。|
|child_changed|リスト内のアイテムに対する変更がないかリッスンします。child_added や child_removed と併用して、リストに対する変更をモニタリングします。|
|child_removed|リストから削除されるアイテムがないかリッスンします。child_added や child_changed と併用して、リストに対する変更をモニタリングします。|
|child_moved|並べ替えられたデータと併用して、アイテムの優先度に対する変更がないかリッスンします。|

> イベント リスナーを追加するには、on() メソッドを使用します。

[公式ドキュメントから抜粋](https://firebase.google.com/docs/database/web/retrieve-data)

要はどのレベルのイベントを気にかけるかということなんですかね。

#### valueイベント
指定したパスにあるコンテンツの静的スナップショットを、イベント発生毎に取得します。

例えば、`/comments` 以下の静的スナップショットをイベント発生毎に取得する場合

こんな感じになります。

```js
// commentsを参照
var commentsRef = firebase.database().ref('comments')
commentsRef.on('value', function(snapshot) {
  updateComments(snapshot.val()); // 取得した際の処理
});
```

<img width="660" alt="Screen Shot 2016-12-14 at 1.28.00.png" src="https://qiita-image-store.s3.amazonaws.com/0/39342/8aeaa371-87ac-c1f0-e3d8-7e29c59dce60.png">

`comments`以下のコンテンツに変更があるたびに、その時の全コンテンツを取得してきます。

`comments`以下のコンテンツを事あるごとに表示！もしくは利用したい！と言うのであればこれでことが足りる気が、、、
一方で、変更があったコンテンツ / 追加されたコンテンツに対して、独自に処理したいのであれば、これでは要件を満たせません。

なので、そこで登場するのが `child`メソッドです。

### childメソッド

> push() メソッドによる新しい子の追加や、update() メソッドによる子の更新など、ノードの子に対して発生した特定の操作に応じて、child イベントがトリガーされます。

[公式ドキュメントから抜粋](https://firebase.google.com/docs/database/web/retrieve-data)

イベントのタイプに合わせて処理が呼べるということかと。
以下、サンプルです！

```js

// commentsを参照
var commentsRef = firebase.database().ref('comments')

// comments以下に追加があった時に発動
commentsRef.on('child_added', function(data) {
  addCommentElement(data.val());
});

// comments以下に追加 / 削除 / 変更があった時に発動
commentsRef.on('child_changed', function(data) {
  setCommentValues(data.val());
});

// comments以下に削除があった時に発動
commentsRef.on('child_removed', function(data) {
  deleteComment(data.val());
});
```

### データの1回読み取り
`once()`メソッドを使用して、１回だけのみトリガーすることが可能です。
※その後再びトリガーされることはありません。

```
// commentsを参照
var commentsRef = firebase.database().ref('comments')

commentsRef.once('value').then(function(snapshot) {
  initCommentElement(snapshot.val());
});
```

今回全て網羅する勢いで書こうと思ったのですが、自分も少しづつ理解しながら書いたので、`value` / `child` の主要なイベントについてのみまとめました！

次は取得編の続きとデータの保存について書きます！