从 Firebase Firestore 迁移到 Supabase
将您的 Firebase Firestore 数据库迁移到 Supabase Postgres 数据库。
Supabase 提供了几个 工具,用于将 Firebase Firestore 数据库中的数据转换为 Supabase Postgres 数据库。该过程会将单个 Firestore collection 的全部内容复制到单个 Postgres table。
Firestore collection 会被“扁平化”并转换为具有以下类型之一的基本列的表:text、numeric、boolean 或 jsonb。如果您的结构更复杂,您可以编写程序将新创建的 json 文件拆分为多个相关表,然后再将您的 json 文件导入 Supabase。
设置迁移工具 #
-
克隆
firebase-to-supabase仓库1git clone https://github.com/supabase-community/firebase-to-supabase.git -
在
/firestore目录中,创建一个名为supabase-service.json的文件,内容如下1{2"host": "database.server.com",3"password": "secretpassword",4"user": "postgres",5"database": "postgres",6"port": 54327} -
在您的项目仪表板上,点击 连接
-
在会话池中,点击连接字符串下“查看参数”。将
Host和User字段替换为显示的值。 -
在
supabase-service.json文件中的password条目中,输入您在创建 Supabase 项目时使用的密码。
生成 Firebase 私钥 #
- 登录到您的 Firebase 控制台 并打开您的项目。
- 点击侧边栏中的 项目概览 旁边的齿轮图标,然后选择 项目设置。
- 点击 服务帐号,然后选择 Firebase Admin SDK。
- 点击 生成新的私钥。
- 将下载的文件重命名为
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 文件#
钩子文件的基本格式如下
1module.exports = (collectionName, doc, recordCounters, writeRecord) => {2 // modify the doc here3 return doc4}参数
collectionName:您正在处理的 collection 的名称。doc:当前正在处理的文档(JSON 对象)。recordCounters:一个内部对象,用于跟踪每个 collection 中处理的记录数量。writeRecord:此函数自动处理将数据写入其他 JSON 文件的过程(对于将文档“扁平化”为写入单独数据库表的单独 JSON 文件很有用)。writeRecord接受以下参数name:要写入的 JSON 文件的名称。doc:要写入文件的文档。recordCounters:传递给此钩子的相同的recordCounters对象(只是传递它)。
示例#
向 collection 添加一个新的(唯一的)数字键#
1module.exports = (collectionName, doc, recordCounters, writeRecord) => {2 doc.unique_key = recordCounter[collectionName] + 13 return doc4}添加从 Firestore 转储记录的时间戳#
1module.exports = (collectionName, doc, recordCounters, writeRecord) => {2 doc.dump_time = new Date().toISOString()3 return doc4}将 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 钩子文件
1module.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 file10 return doc11}结果是两个单独的 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#
联系我们,如果您需要更多帮助来迁移您的项目。