Firebase Cloud Firestoreを使ってみる(Windows)(node.js)(2019/10/5)

# やること

Firebaseで便利に使えるデータベース"Firestore"にデータを書き込み、読み書きしてみます。環境はnode.js。

# 参考にしたサイト

- [Cloud Firestore を使ってみる  |  Firebase](https://firebase.google.com/docs/firestore/quickstart)
- [Firebase Cloud Firestoreを使ってみる - Qiita](https://qiita.com/bathtimefish/items/164d2b0cd268f209db9b)

# プロジェクトの作成

## firebaseポータルからプロジェクトの作成

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147841/29bfc55d-db6b-8b9d-da6c-c237ac001ae5.png)

## プロジェクトに名前を付ける

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147841/4d0c8c22-6205-6c47-055f-3b4e3ed88933.png)

## GoogleAnalyticsは有効化する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147841/09ab0662-7aa2-c649-a1c9-c479c1302988.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147841/9bb7c0ab-724a-8145-9c8f-f1d0cc5a38a8.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147841/4a2cba65-19d1-0c4c-82e4-a6f6aaae06cf.png)

# データベースの作成

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147841/317e4c96-e83b-52a2-7618-abba7cc1ab16.png)

## データベースのセキュリティ保護ルール設定

ひとまずテストモードで作成

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147841/2db83e14-034b-fc7b-fc44-198fcd619dbc.png)

### テストモード
```
rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write;
    }
  }
}
```

### ロックモード
```
rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write: if false;
    }
  }
}
```

## データベースのロケーション設定

asiaを選んでトラブるのは嫌なのでusを選択。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147841/59a5b031-5266-cd24-79fe-64fe587db2f2.png)

データベースが完成

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147841/60dcfb49-9589-11a6-a5d3-0cdecfa8de44.png)

# データベースの初期化

## 環境の作成

```powershell

PS C:\Users\[ユーザー名]> npm install firebase-admin --save                             
> protobufjs@6.8.8 postinstall C:\Users\[ユーザー名]\node_modules\protobufjs
> node scripts/postinstall

npm WARN saveError ENOENT: no such file or directory, open 'C:\Users\[ユーザー名]\package.json'
npm WARN enoent ENOENT: no such file or directory, open 'C:\Users\[ユーザー名]\package.json'
npm WARN sass-loader@7.2.0 requires a peer of webpack@^3.0.0 || ^4.0.0 but none is installed. You must install peer dependencies yourself.
npm WARN vue-chartjs@3.4.2 requires a peer of chart.js@>= 2.5 <= 2.8 but none is installed. You must install peer dependencies yourself.
npm WARN [ユーザー名] No description
npm WARN [ユーザー名] No repository field.
npm WARN [ユーザー名] No README data
npm WARN [ユーザー名] No license field.

+ firebase-admin@8.6.0
added 139 packages from 115 contributors and audited 2232 packages in 36.75s
found 0 vulnerabilities
```
## データベースの初期化

さて、ここでマニュアルでは3つの選択肢が提示される。

- Cloud Functions で初期化する
- Google Cloud Platform で初期化する
- 各自のサーバーで初期化する

この3つのうちどれがいいの?やっぱ、一番上に書いてあるやり方が推奨なの?と初心者ながらに思ってしまったが…。

Cloud FunctionsやGoogle Cloud Platformで実施するやり方が上にあるのは、GCP上で処理を完結させたい人向け。もちろん、それで助かる人もいるし、Googleとしても自社サービスに囲い込みたいはず。その特典として、今から手順を記載するIAMにアクセスしてjsonでうんぬん、は不要だが、GCP以外の環境では動かない。

汎用性のあるやり方は「各自のサーバーで初期化する」なので今回はこちらで実施します。

### Cloud Platform Console で [IAM と管理] > [サービス アカウント] にアクセスします。新しい秘密鍵を生成し、JSON ファイルを保存します。

やってみましょう。

まずは[IAM と管理 > サービス アカウント](https://console.cloud.google.com/iam-admin/serviceaccounts)にアクセスします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147841/216e0c12-608b-6b8c-b923-ecefa44aefe7.png)

どうやらプロジェクトを選択する必要があるので、選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147841/90ee59db-0fc7-99c7-31f7-5f234b563042.png)

プロジェクトに登録されているサービスアカウントが一覧化されるので、上部のボタンからサービスアカウントの追加を実行します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147841/d36dbe35-4853-1dea-1888-aa7449a6bac4.png)

サービスアカウントに名前を付ける必要があるので、名前を付けます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147841/8920f031-cc56-006c-bc2d-aab8d0e1187c.png)

権限を指定する必要があるようです。いったん"オーナー"で指定したけど、これはもっと慎重に検討したほうがいいですね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147841/7e71221d-8939-1c09-4028-34b2aff958c3.png)

この画面でキーの作成を選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147841/7b1ba455-67d4-4e06-8d65-e635a4cbdb3f.png)

キーの作成画面が出てきました。JSONが推奨との事ですし、マニュアルもJSONなのでJSONで作ります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147841/870f4117-0a53-eefa-98ca-ee9898ae4566.png)

JSONが作成されるので、ローカルに保管します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147841/be0ed073-ef9c-2349-6b4c-23039ac8f4f3.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147841/05faf969-2541-87b6-40c7-16b761751c4d.png)

最初の画面に戻ると、新しいサービスアカウントが表示されました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147841/92bb5095-fa2f-531a-6d20-72eb851abb4e.png)

### 次に、このファイルを使用して SDK を初期化します。

やってみましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147841/0eb42019-8bde-63cf-97ac-a2ee0b6f4b36.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147841/fa36be76-a623-d435-fae3-0d51d49c3e3d.png)

特にエラーなく終了しました。

```javascript:index.js

const admin = require('firebase-admin');
let serviceAccount = require('path/to/serviceAccountKey.json');

admin.initializeApp({
  credential: admin.credential.cert(serviceAccount)
});

let db = admin.firestore();
```

この時点ではfirestoreに変化はありません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147841/8e2d8143-48f7-04ae-ece5-35121c49fc65.png)

### データを追加する

index.jsを以下のように編集し、データを追加します。

```javascript:index.js
const admin = require('firebase-admin');
let serviceAccount = require('./myfirstcloudfirestore-8f71042e3ee3.json');

admin.initializeApp({
  credential: admin.credential.cert(serviceAccount)
});

let db = admin.firestore();

// usersコレクションにtaro_yamadaドキュメントを追加
let docTaroYamada = db.collection('users').doc('taroyamada');

let setTaro_yamada = docTaroYamada.set({
  first: 'Taro',
  last: 'Yamada',
  born: 1991
});

// usersコレクションにhanako_satoドキュメントを追加
let docHanakoSato = db.collection('users').doc('hanakosato');

let setHanakosato = docHanakoSato.set({
  'first': 'Sato',
  'last': 'Hanako',
  'born': 1998 ,
  'address': 'tokyo'
});
```

正常にデータが追加されていました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147841/ed0bae5d-0ed0-ffd6-3aef-d822b8af4b17.png)

### データを読み取る

index.jsを以下のように編集し、データを追加します。

```javascript:index.js
const admin = require('firebase-admin');
let serviceAccount = require('./myfirstcloudfirestore-8f71042e3ee3.json');

admin.initializeApp({
  credential: admin.credential.cert(serviceAccount)
});

let db = admin.firestore();

db.collection('users').get()
  .then((snapshot) => {
    snapshot.forEach((doc) => {
      console.log(doc.id, '=>', doc.data());
    });
  })
  .catch((err) => {
    console.log('Error getting documents', err);
  });
```

正常にデータが読み取れました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147841/83943d10-ca89-0f81-25df-9f1df3a58721.png)

### ルールの変更

この状態で誰でもFireStoreにデータを読み書きできてしまうので(…といっても上記で利用したJSONがないと無理だと思いますが)、ルールを少し編集してみます。公式ドキュメントに記載の通り、以下のような記載でルールを変更できるようです。

[Cloud Firestore セキュリティ ルールを使ってみる  |  Firebase](https://firebase.google.com/docs/firestore/security/get-started?authuser=0)

```
service cloud.firestore {
  match /databases/{database}/documents {
    match /<some_path>/ {
      allow read, write: if <some_condition>;
    }
  }
}
```

ひとまず、読み取り可・書き込み不可にしてみました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147841/175efb97-1400-2d76-611f-1e913e9da87d.png)

#### 読み取り

可能です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147841/4988b9fe-0979-c835-555f-9ee18ff14623.png)

#### 書き込み

エラーが出る…かと思いきや出ませんでした。

```javascript:index.js
const admin = require('firebase-admin');
let serviceAccount = require('./myfirstcloudfirestore-8f71042e3ee3.json');

admin.initializeApp({
  credential: admin.credential.cert(serviceAccount)
});

let db = admin.firestore();

// usersコレクションにjiro_suzukiドキュメントを追加
let docJiroSuzuki = db.collection('users').doc('jirosuzuki');

let setJiro_Suzuki = docJiroSuzuki.set({
  first: 'Jiro',
  last: 'Suzuki',
  born: 1995
});
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147841/ab0c1591-7808-e43c-cb46-3d95ce228107.png)

まぁここらへんはおいおい調べていきます。