从 Firebase Firestore 迁移到 Supabase
Migrate your Firebase Firestore database to a Supabase Postgres database.
Supabase 提供了几种 工具 来将数据从 Firebase Firestore 数据库转换到 Supabase Postgres 数据库。这个过程会将单个 Firestore collection 的全部内容复制到单个 Postgres table。
🌐 Supabase provides several tools to convert data from a Firebase Firestore database to a Supabase Postgres database. The process copies the entire contents of a single Firestore collection to a single Postgres table.
Firestore 的 collection 会被“扁平化”,并转换成一个包含基本列的表,这些列的类型可以是 text、numeric、boolean 或 jsonb。如果你的结构比较复杂,你可以写一个程序,把新创建的 json 文件拆分成多个相关的表,然后再将你的 json 文件导入到 Supabase。
🌐 The Firestore collection is "flattened" and converted to a table with basic columns of one of the following types: text, numeric, boolean, or jsonb. If your structure is more complex, you can write a program to split the newly-created json file into multiple, related tables before you import your json file(s) to Supabase.
设置迁移工具 #
🌐 Set up the migration tool [#set-up-migration-tool]
-
克隆
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 私钥 #
🌐 Generate a Firebase private key [#generate-firebase-private-key]
- 登录你的 Firebase 控制台 并打开你的项目。
- 点击侧边栏 项目概览 旁边的齿轮图标,然后选择 项目设置。
- 点击 服务账户,然后选择 Firebase 管理 SDK。
- 点击 生成新的私钥。
- 把下载的文件重命名为
firebase-service.json。
命令行选项 #
🌐 Command line options
列出所有 Firestore 集合 #
🌐 List all Firestore collections
node collections.js
把 Firestore 集合导出到 JSON 文件 #
🌐 Dump Firestore collection to JSON file
node firestore2json.js <collectionName> [<batchSize>] [<limit>]
batchSize(可选)默认为1000- 输出文件名是
<collectionName>.json limit(可选)默认为 0(无限制)
用钩子自定义 JSON 文件 #
🌐 Customize the JSON file with hooks
你可以使用自定义钩子来自定义 JSON 文件的写入方式。一个常见的用法是“扁平化” JSON 文件,或者将嵌套数据拆分成单独的相关数据库表。例如,你可以把一个看起来像这样的 Firestore 文档:
🌐 You can customize the way your JSON file is written using a custom hook. A common use for this is to "flatten" the JSON file, or to split nested data into separate, related database tables. For example, you could take a Firestore document that looks like this:
1[{ "user": "mark", "score": 100, "items": ["hammer", "nail", "glue"] }]然后把它分成两个文件(一个用户表,一个项目表):
🌐 And split it into two files (one table for users and one table for items):
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) #
🌐 Import JSON file to Supabase (Postgres) [#import-to-supabase]
node json2supabase.js <path_to_json_file> [<primary_key_strategy>] [<primary_key_name>]
<path_to_json_file>你在上一步创建的文件的完整路径(Dump Firestore collection to JSON file),例如./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”。
自定义钩子 #
🌐 Custom hooks
Hooks 用来定制将一组 Firestore 文档导出为 JSON 的过程。它们可以用来做以下事情:
🌐 Hooks are used to customize the process of exporting a collection of Firestore documents to JSON. They can be used for:
- 自定义或修改按键
- 正在计算数据
- 把嵌套文档展平成相关的SQL表
写一个自定义 Hook #
🌐 Write a custom hook
为你的收藏创建一个 .js#
🌐 Create a .js file for your collection
如果你的 Firestore 集合叫 users,就在当前文件夹里创建一个叫 users.js 的文件。
🌐 If your Firestore collection is called users, create a file called users.js in the current folder.
构建你的 .js#
🌐 Construct your .js file
钩子文件的基本格式看起来是这样的:
🌐 The basic format of a hook file looks like this:
1module.exports = (collectionName, doc, recordCounters, writeRecord) => {2 // modify the doc here3 return doc4}参数 [#parameters]
🌐 Parameters
collectionName:你正在处理的集合名称。doc:正在处理的当前文档(JSON 对象)。recordCounters:一个内部对象,用来记录每个集合中已经处理了多少条记录。writeRecord:这个函数会自动处理将数据写入其他 JSON 文件的过程(对于把你的文档“平铺”成可以写入不同数据库表的独立 JSON 文件非常有用)。writeRecord接受以下参数:name:要写入的 JSON 文件名。doc:要写入文件的文档。recordCounters:同一个传给这个钩子的recordCounters对象(会传递下去)。
示例 #
🌐 Examples
向集合中添加一个新的(唯一的)数字键 #
🌐 Add a new (unique) numeric key to a collection
1module.exports = (collectionName, doc, recordCounters, writeRecord) => {2 doc.unique_key = recordCounter[collectionName] + 13 return doc4}添加这个记录从 Firestore 导出的时间戳 #
🌐 Add a timestamp of when this record was dumped from Firestore
1module.exports = (collectionName, doc, recordCounters, writeRecord) => {2 doc.dump_time = new Date().toISOString()3 return doc4}把 JSON 展平成单独的文件 #
🌐 Flatten JSON into separate files
把 users 集合拆成单独的文件:
🌐 Flatten the users collection into separate files:
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 钩子文件:
🌐 The users.js hook file:
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 文件:
🌐 The result is two separate JSON files:
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]资源 #
🌐 Resources
迁移到 Supabase #
🌐 Migrate to Supabase
如果你在迁移项目时需要更多帮助,联系我们。