关于 firebase-database
firebase-database 是面向 Flutter 应用的 Firebase Realtime Database 实施指南技能,涵盖数据建模、实时同步、查询、离线行为、在线状态和安全规则。
主要功能
- 01设计扁平化 JSON 数据
- 02查询并索引数据库路径
- 03读取、写入和事务处理数据
- 04配置离线持久化与在线状态
- 05编写并测试安全规则
适用场景
- 01构建低延迟状态同步
- 02跟踪在线状态和连接情况
- 03按常用查询设计数据路径
- 04测试数据库访问与数据验证规则
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ evanca/ flutter-ai-rules --skill firebase-database安装后在 Claude Code 中输入/firebase-database确认已加载。
详细介绍
Firebase Realtime Database 技能
此技能介绍如何在 Flutter 应用中正确实现 Firebase Realtime Database,涵盖数据建模、查询、实时同步、离线支持和安全规则。
适用场景
在使用 Firebase Realtime Database 实现简单数据模型、低延迟同步或在线状态功能时,请使用此技能。对于需要复杂查询和高可扩展性的丰富数据模型,请改用 Cloud Firestore。
1. 数据库选择
在应用需要以下功能时,选择 Realtime Database:
- 简单的数据模型和简单的查找。
- 超低延迟同步(典型响应时间低于 10ms)。
- 默认返回整个子树的深层查询。
- 以任意粒度访问数据,直至单个叶节点值。
- 频繁同步状态,并使用内置在线状态功能。
对于需要可查询性、可扩展性和高可用性的丰富数据模型,请改用 Cloud Firestore。
2. 设置和配置
flutter pub add firebase_database
import 'package:firebase_database/firebase_database.dart';
// After Firebase.initializeApp():
final DatabaseReference ref = FirebaseDatabase.instance.ref();
- 选择最靠近用户的数据库位置。
- 启用持久化以支持离线功能:
FirebaseDatabase.instance.setPersistenceEnabled(true);
FirebaseDatabase.instance.setPersistenceCacheSizeBytes(10000000); // 10MB
设置检查清单
- 确认在访问
FirebaseDatabase.instance前已完成Firebase.initializeApp()。 - 在任何读取或写入操作之前设置持久化。
- 写入测试值并读回,以验证连接状态。
3. 数据结构
- 将数据组织为扁平化 JSON 树——避免深层嵌套。
- 最大嵌套深度为 32 层。
- 设计数据结构以支持最常见的查询。
- 对列表类型的数据使用 push ID 作为唯一标识符:
final newPostKey = FirebaseDatabase.instance.ref().child('posts').push().key;
- 必要时对数据进行反规范化——Realtime Database 不支持联接。
- 自定义键必须采用 UTF-8 编码,最长 768 字节,且不能包含
.$#[]/、ASCII 控制字符 0-31 或 127。
扁平化结构示例
// Instead of nesting chat messages inside rooms:
// rooms/roomId/messages/messageId/...
// Flatten into separate top-level paths:
// rooms/roomId: { name: "General", createdBy: "uid1" }
// room-members/roomId: { uid1: true, uid2: true }
// room-messages/roomId/messageId: { text: "Hello", sender: "uid1", timestamp: ... }
此模式可在不下载所有消息的情况下读取聊天室元数据。
4. 索引和查询
- 查询可以按某个属性排序或筛选,但不能在同一个查询中同时进行两者。
- 在安全规则中使用
.indexOn为频繁查询的字段建立索引:
{
"rules": {
"dinosaurs": {
".indexOn": ["height", "length"]
}
}
}
- 默认情况下,查询是深层查询,会返回整个子树。
- 使用
orderByChild()、orderByKey()或orderByValue()排序:
final query = FirebaseDatabase.instance.ref("dinosaurs").orderByChild("height");
- 使用
limitToFirst()或limitToLast()限制结果数量:
final query = ref.orderByChild("height").limitToFirst(10);
- 使用
startAt()、endAt()和equalTo()进行范围查询:
// Find users whose name starts with "A"
final query = ref.child("users")
.orderByChild("name")
.startAt("A")
.endAt("A\uf8ff");
5. 读取和写入操作
读取一次:
final snapshot = await FirebaseDatabase.instance.ref('users/123').get();
if (snapshot.exists) {
print(snapshot.value);
}
实时监听器:
final subscription = FirebaseDatabase.instance
.ref('users/123')
.onValue
.listen((event) {
final data = event.snapshot.value;
print(data);
});
// Cancel when no longer needed:
subscription.cancel();
每当引用处的数据发生变化时,都会触发 DatabaseEvent,包括子项发生变化的情况。
写入(替换):
await ref.set({
"name": "John",
"age": 18,
"created_at": ServerValue.timestamp,
});
更新(部分更新):
await ref.update({"age": 19});
原子事务:
final result = await FirebaseDatabase.instance
.ref('posts/123/likes')
.runTransaction((currentValue) {
return Transaction.success((currentValue as int? ?? 0) + 1);
});
print('Likes: ${result.snapshot.value}');
多路径原子更新:
final updates = <String, dynamic>{
'posts/$postId': postData,
'user-posts/$uid/$postId': postData,
};
await FirebaseDatabase.instance.ref().update(updates);
- 单次写入操作应低于 256KB。
- 使用监听器获取实时更新,而不是轮询。
6. 面向规模进行设计
- 每个 Realtime Database 最多支持约 200,000 个并发连接和每秒 1,000 次写入。要支持更大规模,请将数据分片到多个数据库实例中。
- 避免存储大型 Blob——文件请使用 Firebase Storage。
- 使用服务器时间戳确保时间记录一致:
await FirebaseDatabase.instance.ref('posts/123/timestamp').set(ServerValue.timestamp);
- 对从多个路径访问的数据采用扇出模式。
- 避免深层嵌套——这会导致数据检索出现性能问题。
7. 离线功能和在线状态
FirebaseDatabase.instance.setPersistenceEnabled(true);
// Keep critical paths synced when offline
FirebaseDatabase.instance.ref('important-data').keepSynced(true);
连接状态和在线状态
// Detect connection state
FirebaseDatabase.instance.ref('.info/connected').onValue.listen((event) {
final connected = event.snapshot.value as bool? ?? false;
if (connected) {
// Set online status and configure onDisconnect cleanup
final presenceRef = FirebaseDatabase.instance.ref('status/${uid}');
presenceRef.set({'online': true, 'last_seen': ServerValue.timestamp});
presenceRef.onDisconnect().set({
'online': false,
'last_seen': ServerValue.timestamp,
});
}
});
- 使用值事件(
onValue)读取数据并接收更新通知——针对在线/离线状态切换进行了优化。 - 仅在只需获取一次数据时使用
get();如果服务器不可用,它会探测本地缓存。 onDisconnect()操作在服务器端执行,即使应用崩溃也能确保完成清理。
8. 安全性
{
"rules": {
"users": {
"$uid": {
".read": "$uid === auth.uid",
".write": "$uid === auth.uid"
}
}
}
}
- 使用
.read、.write、.validate和.indexOn来控制访问并验证数据。 - Realtime Database 中的读写规则会级联——授予访问权限的父级规则无法通过子级规则撤销。
- 在安全规则中使用
auth变量对用户进行身份验证。
数据验证示例
{
"rules": {
"messages": {
"$messageId": {
".validate": "newData.hasChildren(['text', 'sender', 'timestamp'])",
"text": {
".validate": "newData.isString() && newData.val().length <= 500"
}
}
}
}
}
- 使用 Firebase 控制台的规则模拟器全面测试规则。
- 使用 Firebase Emulator Suite 进行本地测试。
参考资料
评论
支持 Markdown