firebase-adminでfirestoreのフィールドを一括変更する方法

# 初めに
Firestoreでアプリを開発していく中で文字列だったデータを配列に変更したい場面があり
データが沢山あり、一つ一つ変更するのが大変だと思いfirebase-adminを使おうと思いました。
それと、変更してもしアプリが動作しなくなっても大丈夫なようにfirestore-export-importも
一緒に使用しようと作成したものを紹介します。

おまけで「firestore-export-importでバックアップおよび復元する方法」も一緒にご紹介します。
## 参考
* [firebase-adminの参考サイト](https://zenn.dev/tama79/articles/9f99823c8aacaf)
* [firestore-export-importの参考サイト](https://www.npmjs.com/package/firestore-export-import)

## 前提
* node v16.15.0
* npm v8.5.5
* firebase-admin v11.0.0
* firestore-export-import v1.2.0
* yarn v1.22.18
### Firestoreのフィールドを変更、追加する時の手順
1. nodeプロジェクトを作成する
1. Firebaseの鍵を取得する
1. 現在のFirestoreのBackUp（export）する
    - `tools/backup.ts`
1. Firestoreのドキュメントにフィールドを一括で変更、追加する
    - `firebase-batch/index.ts`
1. データ変更、追加がうまくいかなったら、BackUp（export）していたデータをimportして復元する　
    - `tools/restore.ts`


``` : ファイル構成
firebase-app/
   ├─　key/
   │   └─　ダウンロードしたjsonファイル
   ├─ firebase-batch/
   │   └─ index.ts
   └─ tools/
       ├─backup.ts
       └─restore.ts
```

## 1. nodeプロジェクトを作成する
1. firebaseフォルダを作成(フォルダ名は任意)
`$ mkdir firebase-app`
2. firebase-appフォルダに移動
`$ cd firebase-app`
3. npmを初期化
`$ yarn init`
4. firebase-adminパッケージを追加
`$ yarn add firebase-admin`
5. firestore-export-importをインストールします。
`npm install firestore-export-import` or `yarn add firestore-export-import`


## 2. Firebaseの鍵を取得
Firebase Admin SDKでFirestoreにアクセスするため、サービスアカウントの .json秘密鍵が必要
新しい秘密鍵の生成からjsonファイルをダウンロードする
![スクリーンショット 2022-08-09 12.02.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2610811/422cd196-ffb5-ec41-0b63-aba3471ee92d.png)

## 3.firestore-export-importを使ってFirestoreのBackUpをする
```typescript: backup.ts
const { initializeFirebaseApp } = require('firestore-export-import')
const  serviceAccount  =  require('../key/先ほどダウンロードしたjsonファイル');
const  appName  =  '[DEFAULT]';

initializeFirebaseApp(serviceAccount, appName);

const  fs  =  require('fs');
const { backup } =  require('firestore-export-import');

backup('users')
.then((collections) => {
    const  json  =  JSON.stringify(collections);
    fs.writeFile('collection-users-backup.json', json, 'utf8',()=>{
        //collection-users-backup.jsonという名前のファイルにusersコレクションのデータが入ります。
        console.log('done');    
        console.log(JSON.stringify(collections));
    });
});
```
ここまで出来たら、実行すればusersコレクションのデータが入ったjsonファイルが作成されます。
実行コマンド`$ node tools/backup.ts`
ファイル名は任意です。
## 4. Firestoreのドキュメントにフィールドを一括で変更、追加する
1. firebase-appフォルダの直下にkeyフォルダを作成し、秘密鍵で取得したjsonファイルを追加する。

1. firebase-appフォルダの直下にfirebase-batchフォルダを作成し、firebase-batchフォルダの直下に下記のファイルを追加する。

```typescript: index.ts
const { initializeApp,cert } = require('firebase-admin/app');
const { getFirestore } = require('firebase-admin/firestore');
const serviceAccount = require('../key/先ほどダウンロードしたjsonファイル');

(async () => {
    try {
        initializeApp({
            credential: cert(serviceAccount),
        });
        const db = getFirestore();
        const querySnapshot = await db.collection('users').get();
        const batch = db.batch();

        querySnapshot.forEach((postDoc) => {
            batch.set(
                //firestoreの[usersコレクション]のadminの値を全て「true」に変更、追加したい時は以下のようにする
                db.collection('users').doc(postDoc.id),
                {
                    //変更、追加したいデータを書く
                    admin: true, 
                },
                { merge: true }
            );
            console.log(postDoc.data().displayName);
        });
        await batch.commit();
    } catch (err) {
        console.log(`Error: ${JSON.stringify(err)}`);
        console.log(err);
    }
})();

```
:::note warn
注意
既存のデータを上書きしないようにするには, merge をtrueに指定する必要があります
ここを指定しないと他の属性が消され、上書きされてしまいます。
:::
ここまで出来たら、実行すればusersコレクションのadminの値をtrueに一括変更、追加出来ます。
実行コマンド`$ node firebase-batch/index.ts`
## 5. firestore-export-importを使ってFirestoreをimportをする

```typescript:restore.ts
const { initializeFirebaseApp, restore } = require('firestore-export-import');
const serviceAccount = require('../key/先ほどダウンロードしたjsonファイル');
const appName = '[DEFAULT]'

initializeFirebaseApp(serviceAccount, appName)
//Backup（export）したファイル
restore('collection-users-backup.json', {
    autoParseDates: true,// timestamp → Date変換
});
```
ここまで出来たら、実行すればBackup(export)したデータがFirestoreに入ります。
実行コマンド`$ node tools/restore.ts`

:::note warn
注意
autoParseDatesをtrueにしないと
そのままFirestoreに{seconds: 161720761, nanoseconds: 51000000}とデータが入ります。
:::