mcpField
F
firebase-database

firebase-database

github.com/evanca数据与数据库663165 次安装3 周前更新
代码仓库

关于 firebase-database

firebase-database 是面向 Flutter 应用的 Firebase Realtime Database 实施指南技能,涵盖数据建模、实时同步、查询、离线行为、在线状态和安全规则。

主要功能

  1. 01设计扁平化 JSON 数据
  2. 02查询并索引数据库路径
  3. 03读取、写入和事务处理数据
  4. 04配置离线持久化与在线状态
  5. 05编写并测试安全规则

适用场景

  1. 01构建低延迟状态同步
  2. 02跟踪在线状态和连接情况
  3. 03按常用查询设计数据路径
  4. 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
设置检查清单
  1. 确认在访问 FirebaseDatabase.instance 前已完成 Firebase.initializeApp()。
  2. 在任何读取或写入操作之前设置持久化。
  3. 写入测试值并读回,以验证连接状态。

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