10
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Firestore に json ファイルからデータを一括インポートする

Last updated at Posted at 2022-12-30

概要

Firebase の Firestore を使っていると、データを一括で Firestore に流し込みたくなるときがあります。
Google Cloud の機能としてインポート/エクスポートがサポートされていますが、こちらは一度エクスポートしたデータをインポートすることしかできません。
データの初期値やマスターデータなど固定のデータを流し込むときはどうすれば良いのでしょうか。
その方法を記述します。

先に結論

結論から書くと、以下のコードを実行することでインポートすることができます。
詳細は下に書いています。

import admin from "firebase-admin";
import importer from "firestore-export-import";
import fs from "fs";

// Firebaseの秘密鍵JSONファイルを読み込み認証情報としてセットする
const serviceAccount = JSON.parse(fs.readFileSync('./secret/secret-key.json', 'utf8'));
admin.initializeApp({
  credential: admin.credential.cert(serviceAccount)
});
// data下のディレクトリ以下のファイルを全部対象にする
fs.readdir('./data/', async function (err, files) {
  if (err) {
    throw err;
  }
  for (const file of files) {
    try {
      // インポート
      await importer.restore('./data/' + file);
    } catch (e) {
      // 1つのファイルが失敗しても処理を止めない
      console.log(e);
    }
  }
});

方法

firestore-export-import というツールを使ってインポーターを作ることで実現できます。

今回は以下のディレクトリ構成でインポーターを作ることにしました。

data/ # インポートするデータを置く場所
  users.json
secret/
  secret-key.json # Firebase の秘密鍵
src/
  import_firestore.ts # インポーター
package.json
tsconfig.json

package.json, tsconfig.json の記述

package.json に必要となるパッケージと scripts を書いておきます。そして npm install します。

package.json
{
    "name": "tools",
    "type": "module",
    "scripts": {
        "import": "./node_modules/.bin/ts-node-esm src/import_firestore.ts"
    },
    "devDependencies": {
        "firebase-admin": "^11.4.1",
        "firestore-export-import": "^1.3.5",
        "ts-node": "^10.9.1",
        "typescript": "^4.9.4"
    }
}

tsconfig.json は好きにしてもらって良いと思いますが、私の設定は以下です。

tsconfig.json
{
    "compilerOptions": {
        "module": "esnext",
        "noImplicitReturns": true,
        "noUnusedLocals": true,
        "moduleResolution": "node",
        "outDir": "lib",
        "sourceMap": true,
        "strict": true,
        "target": "es2020"
    },
    "compileOnSave": true,
    "include": [
        "src"
    ]
}

Firebase の秘密鍵の作成

あらかじめ Firebase コンソールから秘密鍵を作成しておきます。
「プロジェクトの設定」>「サービス アカウント」>「新しい秘密鍵の生成」を押すと生成できます。
それを secret 以下に置いてください(管理は自己責任で)。

スクリーンショット 2022-12-30 21.25.21.png

インポートする JSON ファイルを作成

次に data 下にjsonファイルを配置していきます。
今回は users.json を作って以下のように書きました。1つの JSON ファイルに1つのコレクションを書きます。

{
    "User": {
        "1": {
            "name": "山田太郎",
            "description": "taro yamada"
        },
        "2": {
            "name": "鈴木花子",
            "description": "hanako suzuki"
        },
        "3": {
            "name": "佐藤佳子",
            "description": "yoshiko sato"
        }
    }
}

インポーターの作成

続いて tools 下に import_firestore.ts を作って以下のように記述します。
data 下の JSON ファイル全てを読みに行ってインポートするプログラムです。

import admin from "firebase-admin";
import importer from "firestore-export-import";
import fs from "fs";

// Firebase秘密鍵JSONファイルを読み込み認証情報としてセットする
const serviceAccount = JSON.parse(fs.readFileSync('./secret/secret-key.json', 'utf8'));
admin.initializeApp({
  credential: admin.credential.cert(serviceAccount)
});
// data下のディレクトリ以下のファイルを全部対象にする
fs.readdir('./data/', async function (err, files) {
  if (err) {
    throw err;
  }
  for (const file of files) {
    try {
      // インポート
      await importer.restore('./data/' + file);
    } catch (e) {
      // 1つのファイルが失敗しても処理を止めない
      console.log(e);
    }
  }
});

実行

それでは実行してみます。

$ npm run import

すると...プログラムが成功すると静かに実行終了します。
Firebaseコンソールでimportが成功しているか見てみます。

スクリーンショット 2022-12-30 21.22.49.png

見事インポート成功していました!

Tips: サブコレクションを追加したい場合

コレクション内にサブコレクションを追加したい場合は少し特殊な JSON ファイルの書き方が必要になります。
例えば、キャラクターのコレクション内でスキルのサブコレクションを持ちたい場合、以下のように記述します。

{
    "character": {
        "Ken": {
            "name": "ケン",
            "subCollection": {
                "character/Ken/skill": {
                    "1": {
                        "name": "パンチ"
                    },
                    "2": {
                        "name": "キック"
                    }
                }
            }
        },
        "Ryu": {
            "name": "リュウ",
            "subCollection": {
                "character/Ryu/skill": {
                    "1": {
                        "name": "波動拳"
                    },
                    "2": {
                        "name": "昇竜拳"
                    }
                }
            }
        },
        "Aoi": {
            "name": "アオイ",
            "subCollection": {
                "character/Aoi/skill": {
                    "1": {
                        "name": "かわす"
                    },
                    "2": {
                        "name": "合気道"
                    }
                }
            }
        }
    }
}

これをインポートして Firebase コンソールで見てみると...

スクリーンショット 2022-12-30 21.35.03.png

サブコレクションまでインポート成功していました!

Tips: ローカルの Firestore にデータをインポートしたい場合

エミューレーターで起動したローカルの Firestore にデータをインポートしたい場合はどうすればよいか。
FIRESTORE_EMULATOR_HOST という環境変数がセットされていた場合、自動でそっちへ向くようになっている。
(クレデンシャルの設定があっても無視されるのでコードは一切変える必要がない)
環境変数セット後、インポートを実行すればローカルの firestore にデータが入る。

$ export FIRESTORE_EMULATOR_HOST="localhost:5003"
$ npm run import
10
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?