Firexport指南

如何將 Firestore 資料匯出成 CSV

Firebase 控制台會顯示 Firestore 的資料,卻沒有把它下載成 CSV 的按鈕。要從 Firestore 取得 CSV 檔案,有三種實用的方法。哪一種合適,取決於資料量和你願意做多少準備工作。

更新於 2026年9月24日。 方法 1 中的擴充功能 Firexport 是我們開發的。方法 2 和 3 不需要它。

簡短回答

  • 現在就要某一個查詢的結果: 在控制台的查詢建構工具(Query builder)中執行它,再用瀏覽器擴充功能匯出。 方法 1
  • 需要可重複的匯出,或依自己的方式安排欄位: 一段簡短的 Admin SDK 指令碼。 方法 2
  • 大型集合中的每一份文件,或者你已經在用 BigQuery: 用 gcloud 代管匯出,再透過 BigQuery 產生 CSV。 方法 3
1. 控制台 + 擴充功能2. Admin SDK 指令碼3. gcloud + BigQuery
準備工作安裝一個 Chrome 擴充功能Node.js 和 Google Cloud 憑證Cloud Storage 值區和 BigQuery 資料集
需要啟用計費不需要不需要需要(Blaze 方案)
匯出範圍查詢建構工具中的一個查詢,含其篩選、排序和限制程式碼查詢到的任何內容整個集合
時間戳記依控制台顯示的樣子(Advanced 為 ISO 8601)ISO 8601BigQuery TIMESTAMP
對應和陣列控制台中的文字。較長的值可能被「…」截斷(Advanced 為完整值)一個儲存格內的 JSON經扁平化查詢後,一個儲存格內的 JSON

1. 用 Firexport 從 Firebase 控制台匯出

Firebase 控制台的 Firestore 頁面有一個查詢建構工具(Query builder),可以執行查詢並把結果顯示在 表格中,但沒有任何下載它們的方法。Firexport 是一款免費的 Chrome 擴充功能,會在這些結果旁邊加入一個「匯出」按鈕。

  1. 從 Chrome 線上應用程式商店安裝 Firexport。
  2. 在 Firebase 控制台開啟 Firestore Database,從面板檢視(Panel view)切換到查詢建構工具(Query builder)(「資料」分頁的右上角)。
  3. 在查詢範圍(Query scope)和路徑(Path)下選擇集合,需要的話加入篩選條件或限制, 然後按一下執行(Run)。
  4. 按一下結果上方的匯出。Firexport 會走過結果的每一頁,下載一個 CSV 檔案。要匯出 JSON,開啟按鈕旁的 ⋮ 選單並選擇匯出為 JSON。
Firebase 控制台中的 Firestore 查詢建構工具,以及 Firexport 在查詢結果上方加入的「匯出」按鈕
「匯出」按鈕位於查詢建構工具結果的上方。

檔案裡會有:

  • 一個文件 ID(Document ID)欄,接著每個欄位一欄,順序與控制台表格一致。
  • 值與控制台顯示的一致。在免費版中,時間戳記採用控制台的顯示格式(取決於瀏覽器的語言和時區),參照會被縮短, 較長的對應或陣列可能被「…」截斷。
  • Firexport Advanced(一次性授權)會從控制台已載入的資料中還原 ISO 8601 時間戳記、完整的參照路徑、地理位置點以及 未截斷的對應和陣列。

不需要服務帳戶金鑰,也不需要設定計費:它在你已登入的控制台工作階段中執行,檔案在瀏覽器內產生。它一次匯出一個查詢, 所以子集合只有在以集合群組查詢時才會一起匯出。它可在 Chrome 及其他以 Chromium 為基礎的瀏覽器中執行。

不用指令碼、不用服務帳戶金鑰,直接從控制台匯出你的下一個 Firestore 查詢。

加到 Chrome — 免費

2. 用 Admin SDK 指令碼匯出

如果你不想用擴充功能,或者匯出需要排程執行,一段使用 Firebase Admin SDK 的簡短 Node.js 指令碼就能搞定。它需要一個 能讀取 Firestore 的帳戶:專案 Owner 或 Editor,或者 Cloud Datastore Viewer 角色。

  1. 安裝 SDK:npm install firebase-admin
  2. 登入以取得本機憑證:gcloud auth application-default login。在伺服器上,改為讓 GOOGLE_APPLICATION_CREDENTIALS 指向服務帳戶金鑰。
  3. 把下面的指令碼存成 export-to-csv.mjs,替換 your-project-id,然後執行 node export-to-csv.mjs users。
// Usage: node export-to-csv.mjs users   → writes users.csv
import { writeFileSync } from 'node:fs';
import { initializeApp } from 'firebase-admin/app';
import {
  getFirestore,
  FieldPath,
  Timestamp,
  GeoPoint,
  DocumentReference,
} from 'firebase-admin/firestore';

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

// Read the collection 1,000 documents at a time, so large collections don't time out.
const docs = [];
let last;
while (true) {
  let query = db.collection(collection).orderBy(FieldPath.documentId()).limit(1000);
  if (last) query = query.startAfter(last);
  const page = await query.get();
  if (page.empty) break;
  docs.push(...page.docs);
  last = page.docs[page.docs.length - 1];
}

// Firestore types become plain values: timestamps as ISO 8601, references as paths.
function plain(value) {
  if (value instanceof Timestamp) return value.toDate().toISOString();
  if (value instanceof DocumentReference) return value.path;
  if (value instanceof GeoPoint) return { latitude: value.latitude, longitude: value.longitude };
  if (value instanceof Uint8Array) return Buffer.from(value).toString('base64');
  if (Array.isArray(value)) return value.map(plain);
  if (value && typeof value === 'object') {
    return Object.fromEntries(Object.entries(value).map(([key, v]) => [key, plain(v)]));
  }
  return value;
}

// Maps and arrays go in one cell as JSON. Quote any cell with a comma, a quote or a line break.
function cell(value) {
  if (value === null || value === undefined) return '';
  const text = typeof value === 'object' ? JSON.stringify(value) : String(value);
  return /[",\r\n]/.test(text) ? `"${text.replaceAll('"', '""')}"` : text;
}

const rows = docs.map((doc) => ({ documentId: doc.id, ...plain(doc.data()) }));
// Documents in one collection can have different fields, so the columns are all of them.
const columns = [...new Set(rows.flatMap((row) => Object.keys(row)))];
const lines = [columns, ...rows.map((row) => columns.map((column) => row[column]))];
writeFileSync(`${collection}.csv`, lines.map((line) => line.map(cell).join(',')).join('\r\n'));
console.log(`Wrote ${rows.length} documents to ${collection}.csv`);
  • 要匯出所有父文件下的某個子集合,把 db.collection 改成 db.collectionGroup。
  • 指令碼在寫入檔案之前會把所有資料列放在記憶體中。如果有數百萬份文件,請使用方法 3。

3. 用 gcloud 和 BigQuery 匯出

Firestore 的代管匯出會把備份以 Firestore 自己的格式寫入 Cloud Storage,而不是 CSV。BigQuery 可以載入這種格式並 寫出 CSV。這是大型集合的路線,但需要啟用計費(Blaze 方案),以及執行匯出和寫入值區的權限。Google 的匯出和匯入文件列出了所需的角色。

# 1. Export one collection. BigQuery only loads exports made with --collection-ids.
gcloud firestore export gs://YOUR_BUCKET/users-export --collection-ids=users

# 2. Load it into a BigQuery dataset in the same location as the bucket.
bq --location=US mk --dataset firestore_export
bq load --source_format=DATASTORE_BACKUP firestore_export.users \
  gs://YOUR_BUCKET/users-export/all_namespaces/kind_users/all_namespaces_kind_users.export_metadata

BigQuery 無法把巢狀欄寫入 CSV,而從 Firestore 匯出載入的每個資料表都有一個:存放文件 ID 的 __key__。 所以先用查詢做一份扁平副本,把對應和陣列變成 JSON 文字,再擷取它。

# 3. Make a flat copy: maps and arrays become JSON text. List your own fields.
bq query --use_legacy_sql=false --destination_table=firestore_export.users_flat \
'SELECT __key__.name AS documentId, email, createdAt,
        TO_JSON_STRING(address) AS address, TO_JSON_STRING(tags) AS tags
 FROM firestore_export.users'

# 4. Write it to CSV and download it.
bq extract --destination_format=CSV firestore_export.users_flat gs://YOUR_BUCKET/users.csv
gcloud storage cp gs://YOUR_BUCKET/users.csv .
  • BigQuery 每個檔案最多寫入 1 GB。更多資料請使用萬用字元,例如 gs://YOUR_BUCKET/users-*.csv。
  • 匯出依每份文件一次文件讀取計費。完成後刪除匯出資料夾,以免繼續佔用 Cloud Storage。

常見問題

Firebase 控制台能把 Firestore 資料匯出成 CSV 嗎?

不能。Firebase 控制台的 Firestore 頁面沒有下載按鈕。代管匯出(Google Cloud 控制台的匯入/匯出頁面,或 gcloud firestore export)會把 Firestore 自有格式的備份寫入 Cloud Storage。它用於還原資料,而不是在試算表中開啟。

匯出 Firestore 資料要花錢嗎?

每種方法都會至少讀取一次每份匯出的文件,Firestore 會把這些計為文件讀取。在每日免費配額內不花錢。代管匯出還需要專案啟用計費,其檔案在刪除之前會一直佔用 Cloud Storage。

如何匯出子集合?

把它當作集合群組來查詢。在控制台中,在查詢建構工具的查詢範圍(Query scope)裡選擇集合群組(Collection group)。在指令碼中,用 db.collectionGroup() 取代 db.collection()。使用 gcloud 時,把子集合的 ID 傳給 --collection-ids。

可以改成匯出 JSON 嗎?

可以。Firexport 的匯出選單中有「匯出為 JSON」。指令碼可以用 JSON.stringify(rows) 取代 CSV。在 BigQuery 中,bq extract --destination_format=NEWLINE_DELIMITED_JSON 會保留對應和陣列的巢狀結構。