平台

从 Firebase Firestore 迁移到 Supabase

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


Supabase 提供了几个 工具,用于将 Firebase Firestore 数据库中的数据转换为 Supabase Postgres 数据库。该过程会将单个 Firestore collection 的全部内容复制到单个 Postgres table

Firestore collection 会被“扁平化”并转换为具有以下类型之一的基本列的表:textnumericbooleanjsonb。如果您的结构更复杂,您可以编写程序将新创建的 json 文件拆分为多个相关表,然后再将您的 json 文件导入 Supabase。

设置迁移工具 #

  1. 克隆 firebase-to-supabase 仓库

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

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

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

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

生成 Firebase 私钥 #

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

命令行选项#

列出所有 Firestore collection#

node collections.js

将 Firestore collection 转储到 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
{ "user": "mark", "item": "hammer" },
3
{ "user": "mark", "item": "nail" },
4
{ "user": "mark", "item": "glue" }
5
]

将 JSON 文件导入 Supabase (Postgres) #

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

  • <path_to_json_file> 您在上一步骤中创建的文件的完整路径(将 Firestore collection 转储到 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 表

编写自定义钩子#

为您的 collection 创建一个 .js 文件#

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

构造您的 .js 文件#

钩子文件的基本格式如下

1
module.exports = (collectionName, doc, recordCounters, writeRecord) => {
2
// modify the doc here
3
return doc
4
}
参数
  • collectionName:您正在处理的 collection 的名称。
  • doc:当前正在处理的文档(JSON 对象)。
  • recordCounters:一个内部对象,用于跟踪每个 collection 中处理的记录数量。
  • writeRecord:此函数自动处理将数据写入其他 JSON 文件的过程(对于将文档“扁平化”为写入单独数据库表的单独 JSON 文件很有用)。writeRecord 接受以下参数
    • name:要写入的 JSON 文件的名称。
    • doc:要写入文件的文档。
    • recordCounters:传递给此钩子的相同的 recordCounters 对象(只是传递它)。

示例#

向 collection 添加一个新的(唯一的)数字键#

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

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

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

将 JSON 扁平化为单独的文件#

users collection 扁平化为单独的文件

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

users.js 钩子文件

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

结果是两个单独的 JSON 文件

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

资源#

迁移到 Supabase#

联系我们,如果您需要更多帮助来迁移您的项目。