平台

从Firebase Firestore迁移至Supabase

将您的Firebase Firestore数据库迁移至Supabase Postgres数据库


Supabase 提供了多种工具用于将数据从 Firebase Firestore 数据库迁移到 Supabase Postgres 数据库。该过程会将整个 Firestore collection 的内容复制到单个 Postgres table 中。

Firestore collection 会被"扁平化"处理,并转换为包含以下基本列类型的表:textnumericbooleanjsonb。如果您的数据结构更复杂,可以在将 json 文件导入 Supabase 之前,编写程序将新创建的 json 文件拆分为多个相关联的表。

设置迁移工具

  1. 克隆 firebase-to-supabase 仓库:

    1
    git clone https://github.com/supabase-community/firebase-to-supabase.git
  2. /firestore 目录中,创建一个名为 supabase-service.json 的文件,内容如下:

    1
    2
    3
    4
    5
    6
    7
    { "host": "database.server.com", "password": "secretpassword", "user": "postgres", "database": "postgres", "port": 5432}
  3. 在项目仪表板中,点击连接

  4. 在会话池下,点击连接字符串下方的查看参数。将 HostUser 字段替换为显示的值。

  5. supabase-service.json 文件的 password 字段中输入创建 Supabase 项目时使用的密码。

生成 Firebase 私钥

  1. 登录 Firebase 控制台并打开您的项目
  2. 在侧边栏中点击项目概览旁边的齿轮图标,选择项目设置
  3. 点击服务账户,选择Firebase Admin SDK
  4. 点击生成新的私钥
  5. 将下载的文件重命名为 firebase-service.json

命令行选项

列出所有 Firestore 集合

node collections.js

将 Firestore 集合转储为 JSON 文件

node firestore2json.js <collectionName> [<batchSize>] [<limit>]

  • batchSize (可选) 默认为 1000
  • 输出文件名为 <collectionName>.json
  • limit (可选) 默认为 0 (无限制)

使用钩子自定义 JSON 文件

您可以使用自定义钩子来定制 JSON 文件的生成方式。常见的用途包括"扁平化"JSON 文件,或将嵌套数据拆分为独立的关联数据库表。例如,您可以将如下所示的 Firestore 文档:

1
[{ "user": "mark", "score": 100, "items": ["hammer", "nail", "glue"] }]

拆分为两个文件(一个用户表和一个物品表):

1
[{ "user": "mark", "score": 100 }]
1
2
3
4
5
[ { "user": "mark", "item": "hammer" }, { "user": "mark", "item": "nail" }, { "user": "mark", "item": "glue" }]

将 JSON 文件导入 Supabase (Postgres)

node json2supabase.js <path_to_json_file> [<primary_key_strategy>] [<primary_key_name>]

  • <path_to_json_file> 上一步创建的文件的完整路径(将 Firestore 集合转储为 JSON 文件),例如 ./my_collection.json
  • [<primary_key_strategy>] (可选) 可以是以下之一:
    • none (默认) 不向表添加主键。
    • smallserial 使用 (id SMALLSERIAL PRIMARY KEY) 创建键(自动递增的 2 字节整数)。
    • serial 使用 (id SERIAL PRIMARY KEY) 创建键(自动递增的 4 字节整数)。
    • bigserial 使用 (id BIGSERIAL PRIMARY KEY) 创建键(自动递增的 8 字节整数)。
    • uuid 使用 (id UUID PRIMARY KEY DEFAULT gen_random_uuid()) 创建键(随机生成的 UUID)。
    • firestore_id 使用 (id TEXT PRIMARY KEY) 创建键(使用现有的 firestore_id 随机文本作为键)。
  • [<primary_key_name>] (可选) 主键名称。默认为 "id"。

自定义钩子

钩子用于自定义将 Firestore 文档集合导出为 JSON 的过程。可用于:

  • 自定义或修改键
  • 计算数据
  • 将嵌套文档扁平化为相关的 SQL 表

编写自定义钩子

为集合创建 .js 文件

如果您的 Firestore 集合名为 users,在当前文件夹中创建一个名为 users.js 的文件。

构建您的 .js 文件

钩子文件的基本格式如下:

1
2
3
4
module.exports = (collectionName, doc, recordCounters, writeRecord) => { // 在此处修改文档 return doc}
参数
  • collectionName: 正在处理的集合名称。
  • doc: 当前正在处理的文档(JSON对象)。
  • recordCounters: 内部对象,用于跟踪每个集合中已处理的记录数量。
  • writeRecord: 该函数自动处理将数据写入其他JSON文件的过程(适用于将文档"扁平化"到单独的JSON文件中,以便写入不同的数据库表)。writeRecord接收以下参数:
    • name: 要写入的JSON文件名。
    • doc: 要写入文件的文档。
    • recordCounters: 传递给此钩子的同一个recordCounters对象(仅作传递)。

示例

为集合添加新的(唯一)数字键

1
2
3
4
module.exports = (collectionName, doc, recordCounters, writeRecord) => { doc.unique_key = recordCounter[collectionName] + 1 return doc}

添加从Firestore转储此记录时的时间戳

1
2
3
4
module.exports = (collectionName, doc, recordCounters, writeRecord) => { doc.dump_time = new Date().toISOString() return doc}

将 JSON 扁平化为独立文件

users 集合扁平化为独立文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[ { "uid": "abc123", "name": "mark", "score": 100, "weapons": ["toothpick", "needle", "rock"] }, { "uid": "xyz789", "name": "chuck", "score": 9999999, "weapons": ["hand", "foot", "head"] }]

users.js 钩子文件:

1
2
3
4
5
6
7
8
9
10
11
module.exports = (collectionName, doc, recordCounters, writeRecord) => { for (let i = 0; i < doc.weapons.length; i++) { const weapon = { uid: doc.uid, weapon: doc.weapons[i], } writeRecord('weapons', weapon, recordCounters) } delete doc.weapons // 已移至独立文件 return doc}

结果生成两个独立的 JSON 文件:

1
2
3
4
[ { "uid": "abc123", "name": "mark", "score": 100 }, { "uid": "xyz789", "name": "chuck", "score": 9999999 }]
1
2
3
4
5
6
7
8
[ { "uid": "abc123", "weapon": "toothpick" }, { "uid": "abc123", "weapon": "needle" }, { "uid": "abc123", "weapon": "rock" }, { "uid": "xyz789", "weapon": "hand" }, { "uid": "xyz789", "weapon": "foot" }, { "uid": "xyz789", "weapon": "head" }]

相关资源

企业服务

如需获取项目迁移的更多帮助,请联系我们