google formで回答したらGASを使ってfirebaseに連携し、自動生成したIDを持つドキュメントのデータを書き換える

備忘録です。

自動生成されたドキュメントのID（ランダムな文字列のID）を
ライブラリ「FirestoreApp」で取り出せなかったので、そちらについて特に残しておきたくて書いています。

### つまづきポイント：
GASで今回のライブラリ「FirestoreApp」でwhereを使うところまではできたけれど、
その後、通常firebaseで書く書き方では、ランダムな文字列のIDを取り出せずに悩んだ。

※通常のfirebaseで使う「where」を使った書き方では、
自動生成されたドキュメントのID（ランダムな文字列のID）を取り出せなかった。

#### 今回は：Cloud Firestoreの中のコレクションのドキュメントIDを自動生成している
１）Cloud Firestoreの中に「hoges」コレクションが存在する。
２）hogesコレクションの中には『IDが自動で割り振られたランダムな文字列』のドキュメントが多数ある。
３）hogesコレクション内の各ドキュメントはキー「hogeID」で、値を持っている。

#### やりたいこと：
google formで送信し「fugaID」として受け取った値と、
自動生成されたランダムなIDをもつ各ドキュメントの中にある「hogeID」の値が一致した時に、
そのドキュメント内にあるキー「answerd1」「answerd2」などの値を書き換えたい。


#Google formを準備
googleフォームを作成する。
https://www.google.com/intl/ja_jp/forms/about/

作成したら
右上の「…」から「スクリプトエディタ」を開く。

※スプレッドシートとの連携はこの記事には書かない。他の記事が沢山あるので割愛。
　今回はフォームでの送受信が発生した時に、firebase上の任意の値が書き換わるようにする。

![スクリーンショット 2021-04-06 10.59.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321986/1f8ad5db-8a4e-6ebd-2f54-c742613d406e.png)




#GoogleフォームのスクリプトエディタでGASを書く

## ライブラリを追加
GASのライブラリにFirestoreとつないでデータを書き込むためのライブラリを追加する。
今回は「FirestoreApp」というライブラリを使用する。
https://github.com/grahamearley/FirestoreGoogleAppsScript

左側の「ライブラリ」から

```
1VUSl4b1r1eoNcRWotZM3e87ygkxvXltOgyDZhixqncz9lQ3MjfT1iKFw
```
というIDで検索し、「FirestoreApp」の最新バージョンを追加。

![スクリーンショット 2021-04-06 10.55.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321986/30bdd8e2-ff82-d71c-f008-9649e675620d.png)
![スクリーンショット 2021-04-06 10.55.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321986/a383c8df-29f3-cd06-7104-8999a2ff8719.png)
![スクリーンショット 2021-04-06 10.55.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321986/26143259-7d29-3b43-bd1c-8532b8bf6e6f.png)


## firebaseとの連携
firebaseと連携するための情報をGASに記載する。

### Google Service Accountsからキーを作成して取得

Google Service Accounts page の「サービスアカウント」から
https://console.cloud.google.com/projectselector/iam-admin/serviceaccounts

１）Firebaseのプロジェクトを選択 
２）「サービスアカウントを作成」
３）サービスアカウント名、サービスアカウントIDを入力 -> 作成
４）ロール -> 「Cloud Datastore オーナー」を選択 -> 続行
５）ユーザーロール、管理者ロールは特に設定しなくてもOK　-> 完了
６）作成したサービスアカウントから「鍵を作成」-> キーのタイプは"JSON"にしてローカルに保存。
![スクリーンショット 2021-04-06 12.54.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321986/fa5f227b-c3f8-aa96-89db-f1e3dd1b4a76.png)


### DLしたキーのjsonファイルから必要な情報をGASに書き込む

使うのは先ほどDLしたキーの中の
`project_id` `private_key` `client_email`の3つ。

これらをgoogle formのスクリプトエディタに下記のように書き込む

```javascript
// CloudFirestoreで認証する為の情報
function firestoreDate() {
  var dateArray = {
    'email': 'xxxxxxxxxxxx@xxxxxxxxxxxxxx',
    'key': '-----BEGIN PRIVATE KEY-----\nxxxxxxxxxxx\n-----END PRIVATE KEY-----\n',
    'projectId': 'xxxxxxxxxxxxxxxxxxx'
  }
  return dateArray;
}
```

## フォームから送られてきた回答の文字列と、コレクション内の各ドキュメント内の「任意のキー」の「値」が一致したら、ドキュメントのID（ランダムに生成された文字列ID）を取得→そのドキュメント内の「別のキー」の「値」を変更

続けて先ほど書いた firestoreDate の下に、
下記のように「フォームが送信されたら実行したいスクリプト」を記載する。


```javascript
async function submitForm(e){
  var itemResponses = e.response.getItemResponses();
  // ここにフォームから取得したい回答の値が入る。今回は仮で数字が入る。
  // フォームの質問の1つめの値が入る。
  const num = itemResponses[0].getResponse(); 
  // ここにフォームから取得したい回答の値が入る。今回は仮でID（文字列）が入る。
  // フォームの質問の2つめの値が入る。
  const fugaID = itemResponses[1].getResponse();

  // CloudFirestoreの認証。（上で記載したfirestoreDateを実行している。）
  var dateArray = firestoreDate();
  var firestore = FirestoreApp.getFirestore(dateArray.email, dateArray.key, dateArray.projectId);

  // fugaIDと一致するdocIDの取得
  /* 
  ここでつまずいた。
  通常のwhereの書き方で書けない。
  フォームから送られてきた回答の文字列と、IDが自動生成されているドキュメントの「任意のキー」の「値」が一致したら、
  「ドキュメントのID（自動生成された文字列）」を取得する。
  ※splitで返ってきた文字列をバラバラにして最後尾につくIDの文字列を取得した。
  */
  const ref = await firestore.query('hoges').Where('hogeId', '==', fugaID).Execute();
  const splitText = ref[0].name.split('/')
  const splitLenght = ref[0].name.split('/').length
  const docId = splitText[splitLenght - 1]
  console.log('docId',docId);

  // 更新するobjectのキー
  const answerdNum = `answerd${num}`;

  // 更新するデータ
  /* 
  今回はドキュメント内にある「answerd1」「answerd2」などの値をtrueにする。
  */
  const data = {
    [answerdNum] : true
  }

  // CloudFirestoreをドキュメント更新
  firestore.updateDocument(`hoges/${docId}`, data, true);
}
```

####追記： google formの質問の値から、回答の値をとってくる場合はこんな感じ

```javascript
let num="";
let fugaID="";
var itemResponses = e.response.getItemResponses();
for (var i = 0; i < itemResponses.length; i++) {
  var itemResponse = itemResponses[i];
  var question = itemResponse.getItem().getTitle();
  var answer = itemResponse.getResponse();
  if (question === '質問に入れた文字列'){
    num = answer;
  }
  if (question === '質問に入れた文字列'){
    fugaID = answer;
  }
}
```
何故かfor内のvarはvarじゃないと動かなかった…何故。

## 「フォームが送信されたら実行する」という条件を追加する

google formのスクリプトエディタの左の時計のアイコンから、
フォームが送信されたら「submitForm」を実行する
という条件を追加する。

![スクリーンショット 2021-04-06 13.30.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321986/a36cb4b0-df52-04f8-856e-89d2c5a0ca6c.png)

***

参考にさせていただいた記事🙏：

GAS（Google Apps Script）でCloud Firestoreを利用する時のメモ
https://qiita.com/PmanRabbit/items/a76b9bc5a9d0239c9f78

【書籍管理シリーズ】GASとFireBase(Firestore)を連携させるよ！
https://qiita.com/h_plum/items/f6ba16931f955d33158e

GAS：SpreadSheetに登録したデータをFirestoreに送信する
https://qiita.com/masa-321/items/86e356b02dcf5b840595

***

もっと賢いやり方ありましたら是非教えてください🙏