[Firestore]チュートリアルを試してみた（Web編）

## 概要

- Firebase公式サイトにある[Cloud Firestore データベースを作成する](https://firebase.google.com/docs/firestore/quickstart?hl=ja)を試してみた記録です
- WebからFirestoreへの書き込み/読み取りを実装してみます
- チュートリアルの内容に加えてFirestoreの更新をリアルタイムに検知する手順まで紹介します

## Firestoreのデータベースを作成する

- [Firebaseのコンソール](https://console.firebase.google.com/)で操作していきます
- ログインしたら「プロジェクトを追加」からプロジェクトを作成します
<img width="911" alt="スクリーンショット 2019-09-19 23.18.59.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175213/56899f86-f5b7-afa0-5b78-c6affa22c6d9.png">
<img width="487" alt="スクリーンショット 2019-09-19 23.21.32.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175213/635c6786-2530-57c4-6295-a25f16f892d0.png">
<img width="686" alt="スクリーンショット 2019-09-19 23.22.11.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175213/f18d9b89-c29e-0f6d-773b-2341d75906e9.png">

- プロジェクトの作成には少し時間がかかります
- 作成できたらサイドメニューの「データベース」を選択し「データベースを作成」から作成していきます
<img width="608" alt="スクリーンショット 2019-09-19 23.23.12.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175213/c095aef7-1542-d843-902e-9883bbb050cb.png">

- WebでFirestoreにアクセスする場合はテストモードを選択します

<img width="643" alt="スクリーンショット 2019-09-19 23.26.09.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175213/ebdb75a0-5083-768d-dbe7-6bff51daffee.png">

- 作成が完了したら準備OKです
<img width="895" alt="スクリーンショット 2019-09-19 23.29.45.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175213/c517063b-c14d-503f-bcae-2cd178eb0490.png">

## APIキーの取得

- FirestoreにアクセスするためのAPIキーの情報を控えておく
    - 歯車から「プロジェクトの設定」->「全般」
<img width="712" alt="スクリーンショット 2019-09-20 0.50.02.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175213/a2a53a53-1d20-8275-7cfe-2e2b8fe6eb7c.png">

> この記事で載せているAPIキーはすでに無効化されているものです
> 本来は他者に漏らすことがないように管理すべきものです
> 不用意にGitHubなどにあげてしまわないよう注意してください

## WebからFirestoreにアクセスする

- 適当なディレクトリを作成しセットアップ

```sh
mkdir firestore-sample-web
cd firestore-sample-web
```

- index.htmlを作成する

```html:index.html
<h1>Hello</h1>
<script src="https://www.gstatic.com/firebasejs/6.3.4/firebase-app.js"></script>
<script src="https://www.gstatic.com/firebasejs/6.3.4/firebase-firestore.js"></script>
<script>
  firebase.initializeApp({
    // 控えておいたapiキーとプロジェクトIDを設定する
    apiKey: 'AIzaSyDzPsKbL8V_wDI5FIeqIhE4t6RN25cjgCs',
    projectId: 'firestore-sample-1bd28',
  });

  const db = firebase.firestore();
</script>
```

- ブラウザで表示しコンソールにエラーがでていなければひとまずOK
<img width="612" alt="スクリーンショット 2019-09-20 1.02.06.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175213/0dd9adc9-b757-7634-f9ef-c6c06a001f0a.png">

- データ登録処理を追加
    - ボタンをクリックしたら追加処理をを実行するようにする

```html:index.html
<h1>Hello</h1>
<button id="add">追加</button>
<script src="https://www.gstatic.com/firebasejs/6.3.4/firebase-app.js"></script>
<script src="https://www.gstatic.com/firebasejs/6.3.4/firebase-firestore.js"></script>
<script>
  firebase.initializeApp({
    apiKey: 'AIzaSyDzPsKbL8V_wDI5FIeqIhE4t6RN25cjgCs',
    projectId: 'firestore-sample-1bd28',
  });

  const db = firebase.firestore();

  document.querySelector('#add').addEventListener('click', function() {
    db.collection('users')
      .add({
        first: 'Ada',
        last: 'Lovelace',
        born: 1815,
      })
      .then(function(docRef) {
        console.log('Document written with ID: ', docRef.id);
      })
      .catch(function(error) {
        console.error('Error adding document: ', error);
      });
  });
</script>
```

- 成功すればconsoleにログが出る
<img width="675" alt="スクリーンショット 2019-09-20 1.04.44.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175213/ed406587-b06a-a9a4-baf7-4a2736cf02b5.png">

- Firestoreにデータが追加されたことも確認できる
<img width="634" alt="スクリーンショット 2019-09-19 23.51.43.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175213/37a74804-69da-70a9-4676-c167b95d7214.png">

- さらに追加してみる

```html:index.html
<!-- 省略 -->
<script>
  // 省略
  document.querySelector('#add').addEventListener('click', function() {
    db.collection('users')
      .add({
        first: 'Ada',
        last: 'Lovelace',
        born: 1815,
      })
      .then(function(docRef) {
        console.log('Document written with ID: ', docRef.id);
      })
      .catch(function(error) {
        console.error('Error adding document: ', error);
      });

    // Add a second document with a generated ID.
    db.collection('users')
      .add({
        first: 'Alan',
        middle: 'Mathison',
        last: 'Turing',
        born: 1912,
      })
      .then(function(docRef) {
        console.log('Document written with ID: ', docRef.id);
      })
      .catch(function(error) {
        console.error('Error adding document: ', error);
      });
  });
</script>
```

- 追加ボタンを押すとデータが追加される
<img width="629" alt="スクリーンショット 2019-09-19 23.56.18.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175213/968d33f7-2a07-e082-573f-db6bd38012e5.png">

- 次にデータを取得する処理を追加する
    - 取得ボタンを押すとデータ一覧が表示されるようにする

```html:index.html
<h1>Hello</h1>
<button id="add">追加</button>
<button id="get">取得</button>
<script src="https://www.gstatic.com/firebasejs/6.3.4/firebase-app.js"></script>
<script src="https://www.gstatic.com/firebasejs/6.3.4/firebase-firestore.js"></script>
<script><script>
  // 省略
  document.querySelector('#get').addEventListener('click', function() {
    db.collection('users')
      .get()
      .then(querySnapshot => {
        querySnapshot.forEach(doc => {
          const p = document.createElement('p');
          const result = document.createTextNode(
            `${doc.id} => ${JSON.stringify(doc.data())}`,
          );
          p.appendChild(result);
          document.body.appendChild(p);
        });
      });
  });
</script>
```

- 取得ボタンを押すとFirestoreに保存されている情報を表示できる
<img width="555" alt="スクリーンショット 2019-09-20 1.13.01.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175213/66632903-4f3a-4052-8391-b27d37ed2710.png">

## データの追加をリアルタイムで検知する

- Firestoreへデータが追加されたらリアルタイムに最新データを取得するサンプル
- 新しくreceive.htmlを作成する

```html:receive.html
<div id="result"></div>
<script src="https://www.gstatic.com/firebasejs/6.3.4/firebase-app.js"></script>
<script src="https://www.gstatic.com/firebasejs/6.3.4/firebase-firestore.js"></script>
<script>
  firebase.initializeApp({
    apiKey: 'AIzaSyDzPsKbL8V_wDI5FIeqIhE4t6RN25cjgCs',
    projectId: 'firestore-sample-1bd28',
  });

  const db = firebase.firestore();

  // FirestoreをSubscribeし更新があると処理が実行される
  db.collection('users').onSnapshot(querySnapshot => {
    // 表示内容を全て削除
    document.querySelector('#result').innerHTML = '';

    // デフォルトではコレクションの内容が全件渡される
    querySnapshot.forEach(doc => {
      const p = document.createElement('p');
      const result = document.createTextNode(
        `${doc.id} => ${JSON.stringify(doc.data())}`,
      );
      p.appendChild(result);
      document.querySelector('#result').appendChild(p);
    });
  });
</script>
```

- これまで作成したきたindex.htmlの画面で追加ボタンを押すと、receive.htmlの画面は何もさわっていないのにリアルタイムにデータが表示されていく
![demo.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175213/4ba82a68-8472-ee7f-60e1-ff148118214e.gif)

- このようなリアルタイムに情報を取得できるのはFirestoreの特徴的なところでもあるのでうまく活用すると実装の幅が広がりそう