跳到主要内容

从 FireBase 迁移

本文档帮助您将项目从 FireBase 迁移到云开发 CloudBase。

迁移概览​

功能对照​

FireBaseCloudBase说明
Firestore文档型数据库都是 NoSQL 文档存储
Cloud Functions云函数无服务器函数服务
Cloud Run镜像 http 云函数镜像服务托管
Cloud Storage云存储文件存储服务
Authentication身份认证用户认证服务
Realtime Database实时数据推送实时数据同步

数据迁移​

导出 FireBase 数据​

FireBase DataStorage DataBase 数据导出​

由于 FireBase 官方到导出功能只能导出 Google Cloud Cloud Datastore 的 BigQuery 格式。所以建议通过脚本导出标准的 JSON 格式。

首先需要在在 FireBase 控制台 服务账户界面中创建 FireBase Admin SDK 的密钥,并下载下来。

然后 clone https://github.com/m417z/node-firestore-import-export/tree/fork 分支进入到仓库目录后 执行 npm install && npm run build 触发构建。构建完成后执行

GOOGLE_APPLICATION_CREDENTIALS=<密钥路径> npm run export -- -b firebase-export.json

就能成功将数据库导出到firebase-export.json 中。

导出格式说明
{
"__collections__": {
"albums": {
"HVskzxL7SbQ4CrMV2KoO": {
"description": "A new collection of memories.",
"ownerId": "6TZnxEYS5JVooGWUXf4fvyKBbA33",
"name": "B",
"coverImageUrl": "https://firebasestorage.googleapis.com/...",
"__collections__": {
"photos": {
"3BTRlw1rVSQjfMJzzZ1S": {
"albumId": "HVskzxL7SbQ4CrMV2KoO",
"uploaderId": "6TZnxEYS5JVooGWUXf4fvyKBbA33",
"url": "https://firebasestorage.googleapis.com/...",
"title": "logo.png",
"createdAt": {
"__datatype__": "timestamp",
"value": {
"_seconds": 1770606013,
"_nanoseconds": 801000000
}
},
"location": {
"__datatype__": "geopoint",
"value": {
"_latitude": 32,
"_longitude": 120
}
},
"__collections__": {}
}
}
}
}
}
}
}

其中:

  • 顶层 __collections__ 下是各个集合(如 albums)
  • 集合下的键是文档 ID(如 HVskzxL7SbQ4CrMV2KoO)
  • 文档中的 __collections__ 表示该文档下的子集合(如 photos)
  • timestamp 和 geopoint 等特殊类型会被编码成带 __datatype__ 和 value 的对象,后续在转换脚本中需要还原为 CloudBase 支持的时间戳和 GeoJSON 格式。

FireBase Authentication 导出​

FireBase CLI 具有批量导出用户的功能。 首先安装

npm i -g firebase-cli

登录 FireBase

firebase login

查看 project id

firebase projects:list

最后导出成 json

firebase auth:export user.json --project <上一步骤中获取的project id>
导出格式说明

firebase auth:export 导出的 user.json 是一个包含 users 数组的 JSON 文件,每个元素是一条用户记录,结构大致如下(示例裁剪自实际导出文件,已做脱敏处理):

{
"users": [
{
"localId": "7hQ2mXbK9vP4sT1cUy3Zr8NaLd0w",
"email": "user@example.com",
"emailVerified": false,
"passwordHash": "aS9xK0lmT3p5VnF4c2hDZ0JhR1p5eGd2bE9YUm1qU3hMUG9uRkE9PQ==",
"salt": "c2FsdF9leGFtcGxlX2Jhc2U2NA==",
"createdAt": "1700000000000",
"lastSignedInAt": "1700003600000",
"providerUserInfo": []
}
]
}

数据格式转换​

FireBase 和 CloudBase 的数据格式有差异,需要进行转换。

字段转换对照表​

FireBase 字段/类型CloudBase 字段/格式说明
文档 ID(对象键)_idFireBase 文档 ID 作为对象的键,需提取为 _id 字段
__collections__(删除)子集合标记,需单独处理子集合数据
{"__datatype__": "timestamp", "value": {"_seconds": ..., "_nanoseconds": ...}}毫秒时间戳将 _seconds * 1000 + _nanoseconds / 1000000 转换为毫秒时间戳
{"__datatype__": "geopoint", "value": {"_latitude": ..., "_longitude": ...}}{type: "Point", coordinates: [经度, 纬度]}转换为 GeoJSON 格式,注意坐标顺序为 [经度, 纬度]
createdAt(Timestamp 类型)_createTime如果存在,转换为毫秒时间戳
updatedAt(Timestamp 类型)_updateTime如果存在,转换为毫秒时间戳
userId / ownerId / uploaderId_openid用户相关字段,映射为云开发用户 ID
其他普通字段(完整保留)字符串、数字、布尔值、数组、对象等业务字段

转换示例​

FireBase 原始数据(从导出文件中提取的单个文档):

{
"albumId": "HVskzxL7SbQ4CrMV2KoO",
"uploaderId": "6TZnxEYS5JVooGWUXf4fvyKBbA33",
"title": "logo.png",
"createdAt": {
"__datatype__": "timestamp",
"value": {
"_seconds": 1770606013,
"_nanoseconds": 801000000
}
},
"location": {
"__datatype__": "geopoint",
"value": {
"_latitude": 32,
"_longitude": 120
}
}
}

CloudBase 转换后(文档 ID 3BTRlw1rVSQjfMJzzZ1S 作为 _id):

{
"_id": "3BTRlw1rVSQjfMJzzZ1S",
"albumId": "HVskzxL7SbQ4CrMV2KoO",
"_openid": "6TZnxEYS5JVooGWUXf4fvyKBbA33",
"uploaderId": "6TZnxEYS5JVooGWUXf4fvyKBbA33",
"title": "logo.png",
"_createTime": 1770606013801,
"location": {
"type": "Point",
"coordinates": [120, 32]
}
}

转换说明:

  • 文档 ID(3BTRlw1rVSQjfMJzzZ1S)提取为 _id 字段
  • createdAt 的 Timestamp 转换为毫秒时间戳:1770606013 * 1000 + 801000000 / 1000000 = 1770606013801
  • location 的 GeoPoint 转换为 GeoJSON:[经度, 纬度] = [120, 32]
  • uploaderId 同时保留原字段并映射到 _openid(根据业务需求选择)

导入到 CloudBase​

在控制台操作:

  1. 登录 云开发控制台
  2. 进入「文档型数据库」→「数据管理」
  3. 创建对应的集合
  4. 点击「导入」上传转换后的 JSON 文件
文件大小限制

控制台导入限制最大 50MB。如果数据文件超过此限制,请使用批量写入脚本。

可以参考数据转换脚本示例,请根据项目业务逻辑实际使用的字段名编写脚本生成导入所需的 JSON 文件。

配置安全规则​

由于 CloudBase 使用安全规则替代 FireBase 的安全规则,导入数据后需要配置安全规则:

示例 1:公开读,仅创建者可写

{
"read": true,
"write": "doc._openid == auth.openid"
}

更多安全规则配置请参考 安全规则文档。

云函数迁移​

FireBase Cloud Functions 可以迁移到 CloudBase 云函数。

简单示例​

FireBase Cloud Function:

// FireBase
const functions = require("firebase-functions");

exports.hello = functions.https.onRequest((req, res) => {
const { name } = req.body;
res.json({ message: `Hello, ${name}!` });
});

CloudBase 云函数:

// CloudBase 云函数
exports.main = async (event, context) => {
const { name } = event;
return { message: `Hello, ${name}!` };
};

环境变量迁移​

在云函数控制台配置环境变量,替换原有的 FireBase 环境变量:

FireBase 环境变量CloudBase 替代说明
FIREBASE_PROJECT_IDENV_IDCloudBase 环境 ID
FIREBASE_CONFIG不需要云函数内部自动鉴权

文件存储迁移​

迁移流程​

  1. 下载文件:批量下载 FireBase Storage 中的文件

可以通过 gsutil打包下载 例如:

gsutil -m cp -r "gs://<project prefix>.firebasestorage.app/<subpath>" .
  1. 上传文件:将文件上传到腾讯云开发云存储,可以通过 COS Browser 连接对应 COS 地址批量上传
  2. 更新引用:如有必要,应该更新数据库中的文件引用路径

容器镜像托管迁移​

FireBase 支持 CloudRun 托管容器镜像,可以通过 HTTP 云函数替代。

详细文档请见:云函数部署镜像

部署完成后可通过配置HTTP 网关后访问到。 示例配置文件如下:

{
"envId": "{{envId}}",
"functions": [
{
"name": "helloworld",
"type": "HTTP",
"imageConfig": {
"imageType": "personal",
"imageUri": "ccr.ccs.tencentyun.com/cloudbase/hono-deno-helloworld:amd64"
},
"envVariables": {
"PORT": "9000"
}
}
]
}

需要注意镜像需要是 linux/amd64 架构,并且监听 9000 端口


SDK 对照表​

以下是 FireBase SDK 与 CloudBase SDK 的 API 对照表,帮助您快速完成代码迁移。

初始化​

操作FireBaseCloudBase
初始化 SDKfirebase.initializeApp(config)cloudbase.init({ env })

FireBase:

import { initializeApp } from "firebase/app";
const app = initializeApp({
apiKey: "your-api-key",
authDomain: "your-project.firebaseapp.com",
projectId: "your-project-id",
});

CloudBase:

import cloudbase from "@cloudbase/js-sdk";
const app = cloudbase.init({ env: "your-env-id" });

📖 CloudBase SDK 初始化文档


数据库操作​

操作FireBaseCloudBase
获取数据库引用getFirestore(app)app.database()
获取集合引用collection(db, 'collectionName')db.collection('collectionName')
查询全部getDocs(collectionRef)collection.get()
查询单条getDoc(docRef)collection.doc(id).get()
条件查询where('field', '==', value)collection.where({ field: value })
大于where('field', '>', value)collection.where({ field: _.gt(value) })
小于where('field', '<', value)collection.where({ field: _.lt(value) })
排序orderBy('field', 'asc')collection.orderBy('field', 'asc')
限制数量limit(10)collection.limit(10)
新增数据addDoc(collectionRef, data)collection.add(data)
更新数据updateDoc(docRef, { field: value })collection.doc(id).update({ field: value })
删除数据deleteDoc(docRef)collection.doc(id).remove()

查询示例对比:

// FireBase
import {
collection,
query,
where,
orderBy,
limit,
getDocs,
} from "firebase/firestore";

const q = query(
collection(db, "Todo"),
where("status", "==", "pending"),
where("priority", ">", 5),
orderBy("createdAt", "asc"),
limit(20)
);
const results = await getDocs(q);

// CloudBase
const db = app.database();
const _ = db.command;
const results = await db
.collection("Todo")
.where({
status: "pending",
priority: _.gt(5),
})
.orderBy("createdAt", "asc")
.limit(20)
.get();

📖 CloudBase 数据库 API 文档


云存储操作​

操作FireBaseCloudBase
上传文件uploadBytes(ref, file)app.uploadFile({ cloudPath, filePath })
获取文件 URLgetDownloadURL(ref)app.getTempFileURL({ fileList })
删除文件deleteObject(ref)app.deleteFile({ fileList })
下载文件getBytes(ref)app.downloadFile({ fileID })

上传文件示例对比:

// FireBase
import { ref, uploadBytes, getDownloadURL } from "firebase/storage";

const storageRef = ref(storage, "avatars/avatar.png");
await uploadBytes(storageRef, file);
const url = await getDownloadURL(storageRef);

// CloudBase
const result = await app.uploadFile({
cloudPath: "avatars/avatar.png",
filePath: file,
onUploadProgress: (progressEvent) => {
const percent = Math.round(
(progressEvent.loaded * 100) / progressEvent.total
);
console.log(`上传进度: ${percent}%`);
},
});
const fileID = result.fileID;

📖 CloudBase 云存储 API 文档


云函数操作​

操作FireBaseCloudBase
调用云函数httpsCallable(functions, 'functionName')app.callFunction({ name, data })
定义云函数functions.https.onRequest()exports.main = async (event, context) => {}
获取调用者信息context.authcontext.auth / event.userInfo

调用云函数示例对比:

// FireBase 客户端
import { getFunctions, httpsCallable } from "firebase/functions";

const functions = getFunctions(app);
const hello = httpsCallable(functions, "hello");
const result = await hello({ name: "World" });

// CloudBase 客户端
const result = await app.callFunction({
name: "hello",
data: { name: "World" },
});
console.log(result.result);

📖 CloudBase 云函数 API 文档


身份认证操作​

操作FireBaseCloudBase
获取 Auth 对象getAuth(app)app.auth()
邮箱密码注册createUserWithEmailAndPassword(auth, email, password)auth.signUp({ email, password })
邮箱密码登录signInWithEmailAndPassword(auth, email, password)auth.signInWithEmailAndPassword(email, password)
手机验证码登录signInWithPhoneNumber(auth, phone)auth.signInWithPhoneCode(phone, code)
匿名登录signInAnonymously(auth)auth.signInAnonymously()
获取当前用户auth.currentUserauth.currentUser
退出登录signOut(auth)auth.signOut()

登录示例对比:

// FireBase - 邮箱密码登录
import { getAuth, signInWithEmailAndPassword } from "firebase/auth";

const auth = getAuth(app);
const userCredential = await signInWithEmailAndPassword(
auth,
"email@example.com",
"password"
);
console.log("登录成功:", userCredential.user);

// CloudBase - 邮箱密码登录
const auth = app.auth();
const loginState = await auth.signInWithEmailAndPassword(
"email@example.com",
"password"
);
console.log("登录成功:", loginState.user);

📖 CloudBase 身份认证 API 文档


实时数据库​

操作FireBaseCloudBase
实时监听onSnapshot(docRef, callback)collection.watch()
取消监听unsubscribe()watcher.close()

实时监听示例对比:

// FireBase Firestore
import { onSnapshot } from "firebase/firestore";

const unsubscribe = onSnapshot(docRef, (snapshot) => {
console.log("数据变化:", snapshot.data());
});

// CloudBase 实时数据推送
const db = app.database();
const watcher = db
.collection("messages")
.where({ roomId: "room1" })
.watch({
onChange: (snapshot) => {
console.log("数据变化:", snapshot.docChanges);
},
onError: (error) => {
console.error("监听错误:", error);
},
});

// 取消监听
watcher.close();

📖 CloudBase 实时数据推送文档

更多 API 参考​

类别文档链接
Web SDK 完整文档查看文档
Node.js SDK 文档查看文档
数据库安全规则查看文档
云函数开发指南查看文档
身份认证指南查看文档
云存储使用指南查看文档

常见问题​

Q:FireBase 的安全规则如何迁移?​

CloudBase 使用类似的安全规则语法,但有一些差异。参考 安全规则文档 进行迁移。

Q:实时通信功能如何替代?​

CloudBase 支持实时数据推送,可以使用数据库实时监听功能:

const db = app.database();
db.collection("messages")
.where({ roomId: "xxx" })
.watch({
onChange: (snapshot) => {
console.log("数据变化:", snapshot.docs);
},
});

Q:迁移过程中如何保证业务连续性?​

建议采用渐进式迁移:

  1. 先部署 CloudBase 环境,进行功能测试
  2. 使用双写策略,新数据同时写入两个平台
  3. 完成数据迁移后,逐步切换流量
  4. 确认稳定后,下线 FireBase 服务