Firestore への書き込み、読み込みを最小限のコードと手順でやる（多分）

# やること

Firestore へのデータの書き込み、データの読み込みの方法を思い出すための、最小限のコードと手順をメモしたものです。

# 参考

- [Cloud Firestore を使ってみる](https://firebase.google.com/docs/firestore/quickstart?hl=ja)
- [Firebase Cloud Firestoreの使い方](https://qiita.com/subaru44k/items/a88e638333b8d5cc29f2)

この二つを読めば十分できるんですが、上の記事を読んで「あーなるほど」と思えるレベルまで辿り着く前に、挫折してしまった場合のためのメモです。

# 準備

## 最小限必要なもの

- Google アカウント
- Firebase を使えるようにしておく: 参考 [Firebase で hello world と表示するページを作る方法](https://qiita.com/mml/items/d6e00d8509231051271a): プロジェクトの作成までできればOK
- 適当なブラウザ (Chrome, Edge など) 

## Firebase 側で必要な準備

最低限、プロジェクトひとつの作成と、アプリケーションひとつの作成が必要です。

プロジェクトを作成するには、ブラウザで Firebase コンソールに行きます。

- <a href="https://console.firebase.google.com/u/0/?hl=ja">Firestore コンソール</a>

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/91e0e7df-6a19-133c-a8aa-3f6a9f746b33.png)

コンソールの左上あたるは、上のような表示になっているはずです（絵は違うかもしれない）。ここで「プロジェクトを追加」を押します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/a10ce72d-866e-f5ba-3f55-0771d23cff0f.png)

プロジェクト名を入れるように言われるので、何か入れます。URLとして使える文字列になってる必要があります（多分）。また、他のプロジェクト名と重複していない必要もあるので、長い目の文字列にしておいたほうが良いです（多分）。

入力したら「続行」を押します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/523a4486-01d4-c701-1ea5-2745ef4c0a98.png)

次に Google Analytics の機能をONにするか聞かれます。今回は、プロジェクトをテストに使うだけなので、オフにしておきます。（オンにするとこの次のページでいろいろ設定を聞かれます）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/86832b33-9ffc-f27a-ddd1-692dcae4cfed.png)

「プロジェクトを作成」を押すとこんな画面になるので、待ちます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/87c8fd09-c998-a3db-e95b-e3e6c2e40052.png)

こうなった「続行」を押します。

## アプリケーションの作成

Firestore に Web ページ内からアクセスするあｔめには、最低限ひとつの Web アプリケーションを作っておく必要があります。

プロジェクトを作成したら、下のような画面になります（絵は違うかもしれない）。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/dc514317-c827-206b-89e9-dff19fd1acbd.png)

中央の左に`</>` みたいなアイコンがあって、そこを押すと Web アプリケーションを作成できます。そのアイコンを押します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/c89be146-782a-0e60-02a8-612ed2d8b00a.png)

アプリ名を入れます。Hosting については、今回はローカルでしかテストしないので、使用しないことにします。

これで「作成」を押すと、しばらくしてから次のような画面になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/0a1b5be5-f51b-6194-17f2-d1d8f96a9fa5.png)

上の画面でグレーになっている部分は、javascript で firestore にアクセスするために必要なコードなので、この部分をエディタなどにコピーしておきます。apiKey のところを黒塗りにしてますが、ここにも文字列が入っているはずです。

## apiKey などの情報の再表示

apiKey の情報のコピペを忘れてしまった場合は、下記の手順で再度表示させることができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/8eebe498-3d82-0e32-e38e-677b29792132.png)

まずプロジェクトの画面に行きます。画面の左上あたり「プロジェクトの概要」という項目があります。その右に歯車マークがあるので、それを押します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/e3d4afb6-1fbe-5f46-9de0-6463919debfc.png)

歯車を押して出るメニューから「プロジェクトを設定」を選びます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/ab094533-23a2-ae8b-6fe7-f4d9722012c2.png)

プロジェクト内にあるアプリの一覧が表示されているので、apiKey などの情報が欲しいアプリを探します。「SDKの設定と構成」のところで「CDN」を選ぶと、プロジェクト作成時と同じように javascript のコードが表示されるので、これをコピーします。

## apiKey 公開は大丈夫なのか？

下記がとても参考になります。

- [Firebase apiKey ってさらしていいの? ほんとに?](https://qiita.com/hoshymo/items/e9c14ed157200b36eaa5)

基本的には大丈夫のようですが、後述する firestore 側のルールがテストモードで無制限アクセス可能になっていたりすると、データベースを荒らされたり、無限に課金させられる可能性がありそうです。


後悔
公開する前に、セキュリティルール（後述）は見直しておきましょう。

## firestore でデータベースを作成する

プロジェクトの画面の左のメニューにある Firestore Database のメニューを選びます。すると、下のような画面になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/26b00141-eeb9-ea16-9501-003c0415c773.png)

この画面で「データベースの作成」を押します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/d7b07404-e863-2043-7e6b-6f1d7105403f.png)

セキュリティルールを選択する画面が出るので、ここでは「テストモードで開始する」を押します。

apiKey のところでも書いてますが、この部分は実はかなり重要です。アプリを deploy してテストする場合、apiKey などの情報が公開された状態になるので、テストモードのまま公開すると第三者にデータベースを荒らされる可能性があります。

ローカルでだけテストする場合でも、何かの拍子（たとえば github の public なレポジトリに push したとか）に apiKey などの情報が流出する可能性もあるので、最低限アクセスできる期限くらいは設けたほうが良さそうです（多分）。

詳しくは下記を参照のこと。

- [Firestore 基本的なセキュリティ ルール](https://firebase.google.com/docs/rules/basics?hl=ja)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/6af89a64-82cf-af23-7ed6-f76619dfc105.png)

次にロケーションを選択する画面になります。テストするだけならどこを選んでも良いです。gcp でどこかのロケーションを選択していて、何らか連携する必要がある場合は、それにあわせてロケーションを選びます（異なるロケーション間の通信は料金がかることがあります）。

ロケーションを押して「有効にする」を押すと、プロビジョニングが始まります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/16501a5c-b47f-6703-cc8e-c844be4a1193.png)

プロビジョニングが終了すると、下のような画面になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/f455753f-90cb-32e9-80db-2a6ee8d31560.png)

この状態になれば、さきほどコピペした apiKey などの情報を使って、Firestore Database に読み書きできるようになります。

ちなみに、コマンドラインから firebase コマンドを使って firestore databse を作成することもできます。

```
$ firebase init firestore
```

# firestore を使う

## 最小限に近いコード（多分）

下記をコピペして firestore.html などの名前で作成します。

```firestore.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <title>firestore test</title>
  </head>
  <body>
    <div id="store_sample">
      <input id="words" type="text" value=""/>
      <input type="button" value="送信" onclick="send();"/>
      <input type="button" value="受信" onclick="recieve();"/>
      <br/>
      <div id="output">
      </div>
    </div>

    <script src="https://www.gstatic.com/firebasejs/8.8.0/firebase-app.js"></script>
    <script src="https://www.gstatic.com/firebasejs/8.8.0/firebase-firestore.js"></script>
  
    <script>

    let db;
    let mode = true;
    function init(){
      // 以下、控えておいた情報に書き換える
      let firebaseConfig = {
        apiKey: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", 
        authDomain: "xxxxxxxxxx.firebaseapp.com",
        projectId: "xxxxxxxxxx",
        storageBucket: "xxxxxxxxxx.appspot.com",
        messagingSenderId: "xxxxxxxxxx",
        appId: "xxxxxxxxxx"
      };
      
      firebase.initializeApp(firebaseConfig); // firestore 初期化
      db = firebase.firestore();              // db 初期化
    }

    function send()
    {
      let word = document.getElementById('words').value;
      console.log( word );

      let sample = db.collection("sample"); // コレクション sample 
      
      if ( mode == true ){
        // set はドキュメントの名前を指定して追加する
        // すでに同のドキュメントがあると上書きする
        sample.doc(word).set({ 
          time: firebase.firestore.FieldValue.serverTimestamp()
        });
      }else{
        // set はドキュメントの名前を指定しないで追加する
        // 仕組み的に上書きされることはない。
        sample.add({
          data: word,
          time: firebase.firestore.FieldValue.serverTimestamp()
        }).then(function(e) {
          console.log("success", e);
        }).catch(function(e) {
          console.error("error", e);
        });
      }

    }

    function recieve()
    {
      let output = document.getElementById('output');
      let sample = db.collection("sample"); // コレクション sample 

      // 全部のデータを取得する。
      sample.get().then(e => {
        let arr = [];
        e.forEach(d => {
          let dat = d.data();
          console.log( dat );
          if ( dat.time != null ){
            let t = dat.time.toDate();
            arr.push(t);
          }
        });
        output.innerText = arr.join('：');
      });

    }

    init();

  </script>
  </body>
</html>

```

## 実行

上記ファイルを chrome とか Edge とか Firefox などのブラウザで開くと、下記のような画面になります（多分）。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/b675bc55-4094-7850-3596-42a650690efe.png)

この状態で、テキストフィールドに test と入れて「送信」とします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/6f853dd8-25ce-9545-1d93-f7ebb2891cd7.png)

すると、Firestore のデータベースの画面の中に sample というコレクションが追加されて、その中に test というドキュメントが追加され、データとしてタイムスタンプが登録されるはずです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/a0f99a70-1f09-3d60-3925-17bc4c0bbc76.png)

こうなります。ならない場合は、コードが間違っているか、apiKey などの情報が間違っているか、開いてる Firestore のプロジェクトが間違っているか、セキュリティルールが期限切れなどになっていてアクセスできないか、そのへんのどれかです（多分）。ブラウザのコンソールに、何らかのエラーが出ている可能性があるので、確認します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/e30ebd1e-05e9-648c-42de-f45c1b76e632.png)

このくらいデータを追加したのちに「受信」を押すと、追加されているデータのタイムスタンプ一覧が表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/92e81dd3-1a1f-f56a-a6b8-9fc2d0881727.png)

ここまでできたら、もうできたも同然！

あとは下記を読めば何とかなるはずです（きっと）。

- [Cloud Firestore を使ってみる](https://firebase.google.com/docs/firestore/quickstart?hl=ja)
- [Firebase Cloud Firestoreの使い方](https://qiita.com/subaru44k/items/a88e638333b8d5cc29f2)

コード中にある `mode = true` を `mode = false` にすると、ドキュメント名をランダムかつユニークな文字列にして、入力したテキストはデータとして追加するようになります。

# おわり

firestore にタイムスタンプのデータを入れたい時に、単に `Date.now()`ではだめで、`firebase.firestore.FieldValue.serverTimestamp()` としないといけないようです、逆（デコード？）は `timestamp.toDate()` です。（コード参照のこと）