firestore-export-importしながらfirebase-adminでfirestoreのフィールドを一括変更、追加する方法

631
firestore-export-importしながらfirebase-adminでfirestoreのフィールドを一括変更、追加する方法

初めに

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

おまけで「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プロジェクトを作成する
  2. Firebaseの鍵を取得する
  3. 現在のFirestoreのBackUp(export)する
    tools/backup.ts
  4. Firestoreのドキュメントにフィールドを一括で変更、追加する
    firebase-batch/index.ts
  5. データ変更、追加がうまくいかなったら、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

3.firestore-export-importを使ってFirestoreのBackUpをする

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ファイルを追加する。

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

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をする

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}とデータが入ります。
:::