Firexport指南

如何将 Firestore 数据导出为 JSON

Realtime Database 在 Firebase 控制台里有“导出 JSON”按钮,Firestore 没有。要把 Firestore 文档以 JSON 形式导出,有三种实用的方法,从一个查询的结果到包含子集合的整个集合都能覆盖。

更新于 2026年9月24日。 方法 1 中的扩展程序 Firexport 是我们开发的。方法 2 和 3 不需要它。

简短回答

  • 现在就要某一个查询的结果: 在控制台的查询构建器(Query builder)中运行它,然后用浏览器扩展程序导出。 方法 1
  • 带子集合的集合,或需要可重复的导出: 一段简短的 Admin SDK 脚本。 方法 2
  • 大型集合中的每个文档,或者你已经在用 BigQuery: 用 gcloud 托管导出,再通过 BigQuery 生成 JSON。 方法 3
1. 控制台 + 扩展程序2. Admin SDK 脚本3. gcloud + BigQuery
准备工作安装一个 Chrome 扩展程序Node.js 和 Google Cloud 凭据Cloud Storage 存储桶和 BigQuery 数据集
需要启用结算不需要不需要需要(Blaze 方案)
文件一个 JSON 数组一个 JSON 数组换行分隔的 JSON,每行一个文档
子集合单独导出,作为集合组查询嵌套在每个文档下(可选)单独导出,每个集合 ID 一张表
时间戳按控制台显示的样子(Advanced 为 ISO 8601)ISO 8601BigQuery 时间戳文本

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. 打开导出按钮旁的 ⋮ 菜单并选择导出为 JSON。Firexport 会遍历结果的每一页,下载一个 JSON 文件。(“导出”按钮本身保存的是 CSV。)
Firebase 控制台中的 Firestore 查询构建器,以及 Firexport 在查询结果上方添加的“导出”按钮
“导出”按钮及其 ⋮ 菜单位于查询构建器结果的上方。

文件是一个 JSON 数组,每个文档一个对象:先是 Document ID 键,然后是文档的字段。数字、布尔值和 null 保持它们的 JSON 类型,映射和数组以嵌套形式输出。免费版和 Advanced 的区别在于控制台只以文本显示的那些值:

免费版——时间戳、地理位置点和引用按控制台显示的样子:

[
  {
    "Document ID": "2PomjkgoCISvwnlGrypP",
    "name": "firexport",
    "count": 1,
    "tags": ["dev", "export"],
    "settings": { "theme": "dark", "beta": true },
    "createdAt": "August 24, 2026 at 1:16:09 PM UTC+9",
    "location": "[37.5665° N, 126.978° E]",
    "owner": "/users/u1"
  }
]

Advanced(一次性许可证)——同样的值,从控制台已加载的数据中还原:

[
  {
    "Document ID": "2PomjkgoCISvwnlGrypP",
    "name": "firexport",
    "count": 1,
    "tags": ["dev", "export"],
    "settings": { "theme": "dark", "beta": true },
    "createdAt": "2026-08-24T04:16:09.012207Z",
    "location": { "latitude": 37.5665, "longitude": 126.978 },
    "owner": "projects/my-app/databases/(default)/documents/users/u1"
  }
]

在免费版中,控制台文本无法被重新解析为 JSON 的映射或数组(例如被控制台用“…”截断的那些)会保留为字符串。Advanced 会把它们完整写出。无论哪种,都无需服务账号密钥,也无需设置结算:它在你已登录的控制台会话中运行,文件在浏览器内生成。 它可在 Chrome 及其他基于 Chromium 的浏览器中运行。

不用脚本、不用服务账号密钥,直接从控制台把你的下一个 Firestore 查询导出为 JSON。

添加到 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-json.mjs,替换 your-project-id,然后运行 node export-to-json.mjs users。加上 --subcollections 可以包含每个文档的子集合。
// Usage: node export-to-json.mjs users [--subcollections]   → writes users.json
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, flag] = process.argv.slice(2);
if (!collection) throw new Error('Usage: node export-to-json.mjs <collection> [--subcollections]');
const withSubcollections = flag === '--subcollections';

// Firestore types become JSON 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;
}

// Read a collection 1,000 documents at a time. With --subcollections, each document also gets its
// subcollections under "__collections__", read the same way.
async function readCollection(ref) {
  const docs = [];
  let last;
  while (true) {
    let query = ref.orderBy(FieldPath.documentId()).limit(1000);
    if (last) query = query.startAfter(last);
    const page = await query.get();
    if (page.empty) break;
    for (const doc of page.docs) {
      const row = { documentId: doc.id, ...plain(doc.data()) };
      if (withSubcollections) {
        for (const sub of await doc.ref.listCollections()) {
          row.__collections__ ??= {};
          row.__collections__[sub.id] = await readCollection(sub);
        }
      }
      docs.push(row);
    }
    last = page.docs[page.docs.length - 1];
  }
  return docs;
}

const docs = await readCollection(db.collection(collection));
writeFileSync(`${collection}.json`, JSON.stringify(docs, null, 2));
console.log(`Wrote ${docs.length} documents to ${collection}.json`);
  • 使用 --subcollections 时,每个拥有子集合的文档都会得到一个存放它们的 __collections__ 键,并按实际深度嵌套。查找子集合每个文档要多发一次请求,所以大型集合会更慢。
  • 本身不存在的文档(控制台把它的 ID 显示为斜体)下的子集合,从父集合是够不到的。这类子集合请按集合组导出。
  • 脚本在写入文件之前会把所有内容放在内存中。如果有数百万个文档,请使用方法 3。

3. 用 gcloud 和 BigQuery 导出

Firestore 的托管导出会把备份以 Firestore 自己的格式写入 Cloud Storage,而不是 JSON。BigQuery 可以加载这种格式并 以 JSON 重新写出。这是大型集合的路线,但需要启用结算(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

# 3. Write it out as newline-delimited JSON and download it.
bq extract --destination_format=NEWLINE_DELIMITED_JSON firestore_export.users gs://YOUR_BUCKET/users.json
gcloud storage cp gs://YOUR_BUCKET/users.json .
  • 文件是换行分隔的 JSON:每行一个文档,而不是一个数组。要把它变成数组,运行 jq -s . users.json > users-array.json。
  • 映射和数组保持嵌套。每一行还有一个来自导出的 __key__ 对象,里面存放着文档 ID。
  • BigQuery 每个文件最多写入 1 GB。更多数据请使用通配符,例如 gs://YOUR_BUCKET/users-*.json。
  • 导出按每个文档一次文档读取计费。完成后删除导出文件夹,以免继续占用 Cloud Storage。

常见问题

Firebase 控制台能把 Firestore 数据导出为 JSON 吗?

不能。Realtime Database 的数据查看器菜单里有“导出 JSON”,但 Firestore 的“数据”标签页没有下载功能。托管导出(Google Cloud 控制台的导入/导出页面,或 gcloud firestore export)会把 Firestore 自有格式的备份写入 Cloud Storage,而不是 JSON。

为什么 Firestore REST API 返回 {"stringValue": "..."} 这样的值?

REST API 会把每个字段包在它的类型里:stringValue、integerValue、timestampValue、mapValue 等等。它是 JSON,但不是你文档本来的形状。Admin SDK(方法 2)会替你解开这些类型。

可以把 JSON 导回 Firestore 吗?

不能直接导回。gcloud firestore import 只读取托管导出,而这些 JSON 文件都不是托管导出。要加载 JSON 文件,请用脚本写回去(Admin SDK 的 BulkWriter 能处理大批量写入)。如果目标是恢复数据,请使用托管导出和导入,而不是 JSON。

导出 Firestore 数据要花钱吗?

每种方法都会至少读取一次每个导出的文档,Firestore 会把这些计为文档读取。在每日免费配额内不花钱。托管导出还需要项目启用结算,其文件在删除之前会一直占用 Cloud Storage。