跳到主要内容

从 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
  • timestampgeopoint 等特殊类型会被编码成带 __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 完整文档https://docs.cloudbase.net/api-reference/webv2/initialization
Node.js SDK 文档https://docs.cloudbase.net/api-reference/server/initialization
数据库安全规则https://docs.cloudbase.net/database/security-rules
云函数开发指南https://docs.cloudbase.net/cloud-function/introduce
身份认证指南https://docs.cloudbase.net/authentication/auth/introduce
云存储使用指南https://docs.cloudbase.net/storage/introduce

常见问题

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 服务