バックエンドの知識がない自分がFirestore+GoogleAppsScriptで簡易DBを構築した話

自分へのメモがわりに初投稿です。

# まとめ
- DB使いたい！
- でもバックエンド知識がない:thinking:
- Firestoreを使えばいいじゃない！
- 管理画面からのデータ登録めんどい:head_bandage:
- スプレッドシートに記入してGoogleAppsScriptでFirestoreに一括登録！:hugging:

# この記事について
私は2018年10月ごろ、ほぼ未経験で今の会社に転職し、Androidアプリのエンジニアになりました。
ようやっと業務にも慣れてきまして、そろそろ自分でも趣味でアプリを作ってみたいな、と思い始め。
そんな時にぶち当たった課題をGAS＋Firebaseで解決したお話です。

# DBを使いたいけど…
アプリの詳細は省きますが、よくある「DBからデータを引っ張ってきてリストに表示させる」系の機能を実装しようとしていました。

# バックエンド知識が無い:innocent:
はい。
ものすごく基本的なところからつまづいています。

でも、便利な世の中になったもので、**バックエンド知識がなくてもFirestoreを使えばデータベースを扱える！**ということを私は知っていました。
Firestoreにデータを入力してアプリから叩けばいいじゃん！と。

でもそこにも落とし穴がありました。

# 管理画面からのデータ入力が死ぬほどめんどくさい
皆さまFirestoreを触ったことはあるでしょうか。
Firebaseコンソール画面からのデータ入力はお世辞にも快適とは言えません。
「フィールドの追加」を選択して、「フィールド」と「型」と「値」を入力して…というのをフィールドの数だけ繰り返さなくてはならず、はっきり言って手動ではとてもやってられません。

どうにかこの「データ入力」部分をやりやすくできないか？と調べていて見つけたのが表題のやり方です。

# GoogleAppsScript
ようやく本題です。
Googleスプレッドシートには「GoogleAppsScript(GAS)」というExcelでいうVBAみたいな機能があります。
JSライクなスクリプトを記述することでシートの値を一括で修正したり出来る便利機能です。
このGASを使ってFirebaseとスプレッドシートを連携する方法があると知り、**これだ！**となりました。
（参考：[【書籍管理シリーズ】GASとFireBase(Firestore)を連携させるよ！](https://qiita.com/h_plum/items/f6ba16931f955d33158e)）

以下、実装方法を紹介します。

## 実装

### 注意事項
Firebaseの構築は済んでいる前提です。

### スプレッドシートを作成する
データ入力用の以下のようなスプレッドシートを作成します。
![スクリーンショット 2019-12-23 15.44.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309569/bfad428b-791a-2313-5401-73fe6cc81dfa.png)
1行目がFirestoreに登録する時のフィールド名になります。

### GoogleAppsScriptを作成する
スプレッドシート上から`[ツール] > [スクリプトエディタ]`を選ぶとスプレッドシートに関連付けられたGASが自動的に作成されます。
![スクリーンショット 2019-12-23 15.50.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309569/a0504f6d-e333-8bf9-7213-c993290d2eee.png)

### スプレッドシート上のデータを取得する処理を書く
`コード.gs` というファイルが開くと思うので、下記コードを記載します。
コードは[こちら](https://qiita.com/kingpanda/items/8e60a64dc2454f6ae6b5)を参考にさせて頂きました。

```
var sheetName = '{シート名}'
var book = SpreadsheetApp.getActiveSpreadsheet()
var sheet = book.getSheetByName(sheetName)

var START_ROW = 2
var START_COL = 1

function getSheetValue(sheet) {
  // 1行目（フィールド）の値を取得
  var fieldRange = sheet.getRange(1, 1, 1, sheet.getLastColumn());
  var fieldRowValues = fieldRange.getValues();
  var fields = fieldRowValues[0];
  var rowValues = [];
  var jsonArray = [];
  
  var range = sheet.getRange(START_ROW, START_COL, sheet.getLastRow() - START_ROW + 1, sheet.getLastColumn())
  var values = range.getValues();
  
  for(var i = 0; i < values.length; i++) {
    // １行のデータをpush
    var rowValue = values[i];
    var json = new Object();
    for(var j = 0; j < fields.length; j++) {
      json[fields[j]] = rowValue[j]
    }
    jsonArray.push(json)
  }

  return jsonArray;
}

```

試しにログに出力してみます。
コードに以下の関数を追加し、「関数を選択」から`doOutput` を選んで実行してみましょう。

```
function doOutput() {
  var value = getSheetValue(sheet)
  Logger.log(value)
}
```
![スクリーンショット 2019-12-23 16.14.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309569/0120dcbf-4c31-5968-2c33-fe360b2a6d09.png)



初めて実行する時は下記のような権限リクエストが表示されるので、
許可しておきます。
![スクリーンショット 2019-12-23 15.59.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309569/fdf61548-3848-681f-49c8-3bb7f50ebddb.png)

実行完了後、`[表示] > [ログ]`を確認して以下のようなログが出力されていれば成功です。
![スクリーンショット 2019-12-23 16.16.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309569/83db4806-fb5e-5d14-b070-4eff81944ce5.png)

![スクリーンショット 2019-12-23 16.16.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309569/60c0f9f9-6619-7303-a096-03b6dd95b4b5.png)

### 取得したデータをFirestoreに出力する
いよいよFirestoreへの出力処理です。
出力処理は[GAS：SpreadSheetに登録したデータをFirestoreに送信する](https://qiita.com/masa-321/items/86e356b02dcf5b840595)を参考にさせて頂きました。

Firestoreへの接続には、[grahamearley/FirestoreGoogleAppsScript](https://github.com/grahamearley/FirestoreGoogleAppsScript)さんのライブラリを使います。

#### ライブラリの追加
`[リソース] > [ライブラリ] > [ライブラリを追加]`から、

```
1VUSl4b1r1eoNcRWotZM3e87ygkxvXltOgyDZhixqncz9lQ3MjfT1iKFw
```

というコードを入力します。
バージョンは現在22が最新になっています。
![スクリーンショット 2019-12-23 16.26.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309569/03e5f22e-72fc-a124-4d98-1b44721cc3c3.png)

#### 秘密鍵の取得
ライブラリを追加したら、次にFirestoreへの接続に必要な秘密鍵を取得します。
Firebaseのコンソール画面から、`[プロジェクトの設定(Project OverViewの右の歯車マーク)] > [サービスアカウント] > [新しい秘密鍵の作成]`を選択します。
![スクリーンショット 2019-12-23 16.33.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309569/98a7b902-c750-86ad-46b9-1aeb736e746a.png)
生成されたjsonファイルを元に、下記の関数を`コード.gs`に追加します。

```
// Firestoreへ認証する為のデータ情報を設定
function firestoreCertification() {
  var certification = {
    "email": "{client_emailの値}", 
    "key": "-----BEGIN PRIVATE KEY-----\n{private_keyの値}\n-----END PRIVATE KEY-----\n",
    "projectId": "{project_idの値}"
  }
  return certification;
}
```

これで指定したFirestoreにアクセス出来るようになります。
Firestoreへのドキュメント書き込み処理が以下です。

```
// Firestoreにデータ作成
function createFirestoreDocuments() {
  var arrayData = getSheetValue(sheet);
  arrayData.forEach(createDocument)
}

function createDocument(item) {
  var certArray = firestoreCertification();
  var firestore = FirestoreApp.getFirestore(certArray.email, certArray.key, certArray.projectId);

   firestore.createDocument('document/'+ item.id, item);
}
```

作成した`createFirestoreDocuments`関数を実行すると、
Firestoreの`document`コレクション内に、スプレッドシートの内容が追加されました！
![スクリーンショット 2019-12-23 16.58.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309569/6c6ef055-111b-f22c-b226-b8b3a1d7e3c4.png)

# さいごに
私のような雑魚エンジニアでもDBっぽいものを扱えるようになるFirestore+GoogleAppsScript最高！という記事でした。
少しでも似たような境遇の人（いる？）のお役に立てれば幸いです。