Firexportガイド

CSV と JSON を Firestore にインポートする方法

Firebase コンソールで Firestore にドキュメントを入れる手段は、1 件ずつ追加するドキュメントを追加(Add document)だけで、ファイルを読み込むボタンはありません。Google 自身のインポートである gcloud firestore import が読むのは Firestore 独自のエクスポート ファイルだけで、CSV や JSON は読めません。ファイルをコレクションに入れる方法は 3 つあります。どれが合うかは、ファイルの大きさと、ファイルがどこから来たかによります。

2026年10月21日 更新。 方法 1 の拡張機能 Firexport は私たちのものです。方法 2 と 3 には不要です。

結論から言うと

  • いま、CSV か JSON のファイルを 1 つのコレクションに入れたい: コンソールのパネルビュー(Panel view)からブラウザ拡張機能でインポートします。 方法 1
  • とても大きなファイル、スケジュールで実行するジョブ、または独自の変換: 短い Admin SDK スクリプト。 方法 2
  • 別のプロジェクトやバックアップからデータベース全体を移したい: gcloud のマネージド エクスポートとインポート(CSV や JSON は読みません)。 方法 3
1. コンソール + 拡張機能2. Admin SDK スクリプト3. gcloud のマネージド インポート
準備Chrome 拡張機能をインストールし、Google アカウントを接続Node.js と Google Cloud の認証情報Cloud Storage バケットと gcloud
読み込めるものCSV、JSON、JSON Lines、または貼り付けたテキストCSV、JSON、JSON Lines(コードが読むもの)Firestore 独自のエクスポート ファイルだけ
フィールドのタイプフィールドごとに、プレビューを見ながら選ぶコードが変換するものエクスポートのまま
既存のドキュメントそのままにする、置き換える、統合するcreate、set、merge上書きされる
課金の有効化不要不要必要(Blaze プラン)

1. Firexport で Firebase コンソールからインポート

Firexport は、Firestore のパネルビュー(Panel view)で、各コレクションのドキュメントを追加(Add document)の行の右端にインポート アイコンを追加する無料の Chrome 拡張機能です。接続した Google アカウントで書き込むので、サービス アカウント キーもコードの準備も不要です。

  1. Chrome ウェブストアから Firexport をインストールします。
  2. Firebase コンソールで Firestore Database > データ(Data)をパネルビュー(Panel view)で開き、インポート先のコレクションをクリックします。
  3. ドキュメントを追加(Add document)の行の右端にあるインポート アイコンをクリックします。
  4. CSV、JSON、JSON Lines のファイルを選ぶかドロップします。またはテキストを貼り付けに切り替えて、読み込むをクリックします。
  5. 各フィールドのタイプと、ドキュメント ID をどこから取るかを確認し、ドキュメントがすでにある場合の動作を選びます。
  6. 初回は、ウィンドウから Google アカウントを接続するよう求められます。プロジェクトに書き込めるアカウントを選び、Google のウィンドウでアクセスを許可します。そのあとインポートをクリックします。
Firebase コンソールの Firestore のパネルビュー(Panel view)と、Firexport がドキュメントを追加(Add document)の行の端に追加したインポート アイコン
インポート アイコンは、データを入れたいコレクションのドキュメントを追加(Add document)の右端にあります。
CSV を読み込んだあとのインポート ウィンドウ。ドキュメント 3 件、フィールド 8 個と、フィールドごとに選んだタイプが表示されている
各列は、提案されたタイプつきのフィールドになります。Document ID 列はドキュメント ID になります。

フィールドのタイプとドキュメント ID

  • CSV のセルはテキストで、JSON にはタイムスタンプも参照もありません。そこで Firexport は、各フィールドの値からタイプを提案します。文字列、整数、数値 (double)、ブール値、タイムスタンプ、参照、ジオポイント、バイト (base64)、またはインポートしない、のいずれかです。提案するのはすべての値が合うときだけで、どれも変更できます。
  • タイムスタンプは ISO 8601(2026-10-01T09:30:00Z)、ブラウザのタイムゾーンでの 2026-10-01 09:30:00、またはミリ秒で書けます。参照は users/u1 のようなパスで書けます。マップと配列の中の値は JSON のタイプのままなので、ネストしたデータは JSON に入れてください。CSV の列は常に最上位のフィールド 1 つになります。
  • ドキュメント ID は、選んだ列、JSON オブジェクトのキー、または新しいランダム ID から取ります。Document ID 列は自動で選ばれるので、Firexport でエクスポートしたファイルはそのままインポートできます。/users/u1 のようにパスで書かれた ID は最後の区切りを使います。
  • プレビューには、最初のドキュメントが書き込まれるとおりの形で、各値のタイプとともに表示されます。タイプに合わない値や重複した ID など、書き込めない行は一覧に表示され、何かを送る前に除外されます。

ドキュメントがすでにある場合

デフォルトのそのままにするは、新しいドキュメントだけを作成します。ID がすでにある行は失敗し、一覧に表示されます。置き換えるでは、ドキュメントはファイルにあるフィールドだけになります。統合するは、ファイルのフィールドをマップの中まで書き込み、ドキュメントのほかのフィールドは残します。新しいランダム ID が既存のドキュメントと重なることはありません。

既存のドキュメントに対する 3 つの選択肢、最初のドキュメントのタイプつきプレビュー、「ドキュメント 3 件をインポート」ボタン
開始する前に、ドキュメントの書き込み先がウィンドウに表示されます。

ドキュメント 1 件が Firestore の書き込み 1 回で、プロジェクトに課金されます。Firexport は毎秒最大 500 回の書き込みを送り、一時的な理由で失敗した書き込みは再試行します。すべての行を書き込むと、ウィンドウは短い通知を出して閉じます。失敗した行があれば一覧にし、CSV のレポートを用意し、再開もできます。書き込みは接続したアカウントの権限で行われるので、セキュリティ ルールは適用されません。ファイルはブラウザから直接 Google に送られ、私たちには一切送られません。ファイルと貼り付けたテキストは 100 MB まで扱えます。

スクリプトもサービス アカウント キーもなしで、CSV や JSON のファイルをコンソールから Firestore にインポートしましょう。

Chrome に追加 — 無料

2. Admin SDK スクリプトでインポート

100 MB を超えるファイル、スケジュールで実行するインポート、独自の変換には、Firebase Admin SDK を使う Node.js スクリプトで行を直接書き込みます。下のスクリプトは、ヘッダー行つきの CSV、JSON 配列、ドキュメント ID をキーにした JSON オブジェクト、または JSON Lines を読み込み、1 行につき 1 つのドキュメントを書き込みます。Firestore に書き込めるアカウントが必要です。プロジェクトのオーナーか編集者、または Cloud Datastore ユーザーのロールです。

  1. SDK と CSV パーサーをインストール: npm install firebase-admin csv-parse
  2. ローカルの認証情報でサインイン: gcloud auth application-default login。サーバーでは代わりに GOOGLE_APPLICATION_CREDENTIALS でサービス アカウント キーを指定します。
  3. 下のスクリプトを import-to-firestore.mjs として保存し、your-project-id を置き換え、TYPES を自分のフィールドに合わせて、node import-to-firestore.mjs orders.csv orders を実行します。
// Usage: node import-to-firestore.mjs orders.csv orders   → one document per row in orders
// Reads .csv (with a header row), .json (an array, or an object keyed by document ID) and .jsonl.
import { readFileSync } from 'node:fs';
import { initializeApp } from 'firebase-admin/app';
import { getFirestore, Timestamp } from 'firebase-admin/firestore';
import { parse } from 'csv-parse/sync';

initializeApp({ projectId: 'your-project-id' });
const db = getFirestore();
const [file, collection] = process.argv.slice(2);
if (!file || !collection) throw new Error('Usage: node import-to-firestore.mjs <file> <collection>');

// The column or key that holds each document's ID. Rows without one get a random ID.
const ID_FIELD = 'Document ID';
// CSV cells are all text and JSON has no timestamps: list the fields to convert. The rest stay as they are.
const TYPES = { createdAt: 'timestamp', items: 'integer', total: 'number' };
// 'create' never touches an existing document (that row fails), 'set' replaces it, 'merge' adds to it.
const MODE = 'create';

const text = readFileSync(file, 'utf8');
const isCsv = file.endsWith('.csv');
let rows;
if (isCsv) {
  rows = parse(text, { columns: true, bom: true, skip_empty_lines: true });
} else if (file.endsWith('.jsonl')) {
  rows = text.split('\n').filter((line) => line.trim()).map((line) => JSON.parse(line));
} else {
  const json = JSON.parse(text);
  rows = Array.isArray(json) ? json : Object.entries(json).map(([id, data]) => ({ [ID_FIELD]: id, ...data }));
}

function convert(type, value) {
  if (type === 'timestamp') {
    const date = new Date(/^\d+$/.test(value) ? Number(value) : value); // ISO 8601 or milliseconds
    if (Number.isNaN(date.getTime())) throw new Error(`not a timestamp: ${value}`);
    return Timestamp.fromDate(date);
  }
  if (type === 'integer' || type === 'number') {
    const number = Number(value);
    if (value === '' || !Number.isFinite(number) || (type === 'integer' && !Number.isInteger(number))) {
      throw new Error(`not ${type === 'integer' ? 'an integer' : 'a number'}: ${value}`);
    }
    return number;
  }
  if (type === 'boolean') return value === true || value === 'true';
  return value;
}

// Convert every row before writing anything, so a bad value stops the import instead of half of it.
const docs = rows.map((row, index) => {
  const data = {};
  for (const [field, value] of Object.entries(row)) {
    if (field === ID_FIELD || (isCsv && value === '')) continue; // an empty CSV cell is a missing field
    try {
      data[field] = TYPES[field] ? convert(TYPES[field], value) : value;
    } catch (error) {
      throw new Error(`Row ${index + 1}, ${field}: ${error.message}`);
    }
  }
  const id = row[ID_FIELD] ? String(row[ID_FIELD]).split('/').pop() : undefined; // a path keeps its last part
  return { row: index + 1, ref: id ? db.collection(collection).doc(id) : db.collection(collection).doc(), data };
});

// BulkWriter sends the writes in batches, keeps under Firestore's rate limits and retries what can be retried.
const writer = db.bulkWriter();
const failures = [];
for (const { row, ref, data } of docs) {
  const write = MODE === 'create' ? writer.create(ref, data) : writer.set(ref, data, { merge: MODE === 'merge' });
  write.catch((error) => failures.push(`Row ${row} (${ref.id}): ${error.message}`));
}
await writer.close();
console.log(`Wrote ${docs.length - failures.length} of ${docs.length} documents to ${collection}`);
failures.forEach((failure) => console.log(failure));
  • CSV のセルはテキストです。スクリプトは TYPES にあるフィールドだけを変換し、残りは文字列のままにします。空のセルはフィールドなしになります。JSON の値はタイプを保ち、マップと配列はそのまま書き込まれます。ただし、配列の中に直接ある配列は例外で、Firestore が受け付けません。
  • 何かを書き込む前にすべての行を変換するので、不正な値があると、インポートを途中まで残すのではなく、その行とフィールドを示してスクリプトが止まります。
  • MODE が 'create' なら、既存のドキュメントには手を付けず、その行は失敗として一覧に出ます。'set' は置き換え、'merge' はファイルのフィールドを追加します。ID のない行は実行のたびに新しいランダム ID になるので、スクリプトを 2 回実行するとそれらの行は重複します。
  • BulkWriter は書き込みをまとめ、毎秒 500 回から始めて Firestore の 500/50/5 ルールが許す範囲で増やし、一時的な理由で失敗した書き込みを再試行します。コレクションには users/u1/orders のようなサブコレクションのパスも指定できます。方法 1 と同じくセキュリティ ルールは適用されず、ドキュメント 1 件が書き込み 1 回です。

3. gcloud のマネージド インポートでデータベース全体をコピー

gcloud firestore import(Google Cloud コンソールの Firestore のインポート/エクスポート ページにもあります)は、Firestore のマネージド インポートです。読むのは gcloud firestore export が Cloud Storage バケットに書き出した Firestore 独自の形式のものだけで、CSV や JSON は読みません。バックアップの復元や、別のプロジェクトやデータベースへコレクションをタイプを保ったままコピーするのに使います。

# 1. Export the collection from the source project.
gcloud firestore export gs://YOUR_BUCKET/orders-export --collection-ids=orders --project=source-project-id

# 2. Import that export into the destination project.
gcloud firestore import gs://YOUR_BUCKET/orders-export --project=destination-project-id
  • 課金の有効化(Blaze プラン)が必要です。インポートはドキュメントごとに 1 回の書き込みです。
  • インポートは同じ ID のドキュメントを上書きし、ほかのドキュメントはそのまま残します。Cloud Functions はトリガーされません。
  • アカウントには、オーナー、Cloud Datastore オーナー、または Cloud Datastore インポート / エクスポート管理者のロールが必要です。別のプロジェクトのバケットからインポートするには、インポート先プロジェクトの Firestore サービス エージェントである service-PROJECT_NUMBER@gcp-sa-firestore.iam.gserviceaccount.com に、そのバケットへのアクセス権が必要です。

FAQ

Firebase コンソールから CSV や JSON のファイルを Firestore にインポートできますか?

いいえ。Firestore のデータタブではドキュメントを追加(Add document)でドキュメントを 1 件ずつ追加するだけで、gcloud firestore import は Firestore 独自のエクスポート ファイルしか読みません。CSV や JSON のファイルを読み込むには、Admin SDK スクリプトか、コンソールにインポートを追加する Firexport のようなブラウザ拡張機能が必要です。

JSON ファイルを Firestore にどうインポートしますか?

ドキュメントごとに 1 つのオブジェクトを持つ JSON 配列か、ドキュメント ID をキーにしたオブジェクトを使います。Firexport では、コレクションのドキュメントを追加(Add document)の行にあるインポート アイコンをクリックしてファイルを選びます。マップと配列は JSON のタイプのままです。Admin SDK では、上のスクリプトのように、ファイルを読み込んで各オブジェクトを BulkWriter で書き込みます。

タイムスタンプや参照はどうインポートされますか?

CSV と JSON は Firestore のタイプを持てないので、ファイルの中のタイムスタンプは、何かが変換するまでただのテキストです。Firexport は、フィールドのタイプをタイムスタンプ、参照、ジオポイントにすると変換します。スクリプトでは、たとえば Timestamp.fromDate(new Date(value)) や db.doc(path) で自分で変換します。

インポートにセキュリティ ルールは適用されますか?

いいえ。Firexport のインポート、Admin SDK、gcloud はどれもアカウントの IAM 権限で書き込み、セキュリティ ルールが適用されるのはクライアント SDK だけです。インポートする前に、データとアカウントを確認してください。

Firestore へのインポートにはどれくらい費用がかかりますか?

どの方法でも、インポートするドキュメント 1 件が書き込み 1 回です。無料の Spark プランでは 1 日 20,000 回の書き込みから差し引かれ、それを超えた書き込みは割り当てがリセットされるまで失敗します。Blaze プランでは、無料枠を超えた書き込みはデータベースのロケーションの料金で課金されます。