将 Cloud Firestore 和 Firebase Realtime Database 配合使用

您可以在应用中同时使用 Firebase 实时数据库和 Cloud Firestore,并利用每种数据库解决方案的优势来满足您的需求。例如,您可能希望利用 Realtime Database 对在线状态的支持,如在 Cloud Firestore 中构建在线状态系统中所述。

详细了解不同数据库之间的差异

将数据移至 Cloud Firestore

如果您已决定要将部分数据从 Realtime Database 迁移到 Cloud Firestore,请考虑以下流程。由于每种数据库都有独特的需求和结构方面的注意事项,因此没有自动迁移途径。不过,您可以按照以下常规步骤进行操作:

  1. 将数据结构和安全规则从 Realtime Database 映射到 Cloud Firestore。Realtime Database 和 Cloud Firestore 均依赖于 Firebase Authentication,因此您无需为您的应用更改用户身份验证机制。不过,由于安全规则和数据模型有所不同,因此在开始将数据迁移到 Cloud Firestore 之前,请务必仔细考虑这些差异。

  2. 移动历史数据。在 Cloud Firestore 中设置新的数据结构时,您可以将现有的数据从 Realtime Database 映射并移动到新的 Cloud Firestore 实例。但是,如果要在应用中同时使用这两种数据库,则无需将历史数据从 Realtime Database 中移出。

  3. 将新数据实时镜像到 Firestore。将新数据添加到 Realtime Database 的同时,使用 Cloud Functions 将其写入新的 Cloud Firestore 数据库。

  4. 将 Cloud Firestore 作为迁移后的数据的主要数据库。迁移部分数据后,将 Cloud Firestore 作为主要数据库来使用,并对迁移后的数据减少 Realtime Database 的使用。考虑为处理这些数据仍与 Realtime Database 绑定的应用的版本,以及您打算如何继续为其提供支持。

请确保同时考虑 Realtime DatabaseCloud Firestore结算费用

映射您的数据

Realtime Database 中的数据采用单树结构,而 Cloud Firestore 则通过文档、集合和子集合支持更明晰的数据层次结构。如果您将部分数据从 Realtime Database 移动到 Cloud Firestore,可以考虑针对您的数据采用一种不同的体系结构。

要考虑的主要差异

如果您将数据从现有的 Realtime Database 树移动到 Cloud Firestore 文档和集合,请注意数据库之间的以下主要差异(这些差异可能会影响在 Cloud Firestore 中设置数据结构的方式):

  • 浅查询可在分层数据结构中提供更高的灵活性。
  • 复杂查询能够实现更高的细化程度,并减少对重复数据的需求。
  • 查询游标可提供更强大的分页功能。
  • 事务不再要求所有数据共用一个根,并且效率更高。
  • Realtime Database 和 Cloud Firestore 的结算费用会有所不同。在很多情况下,Cloud Firestore 可能比 Realtime Database 的费用更高,尤其是在依赖大量小操作时。您可以考虑减少对数据库的操作次数,并避免不必要的写入。详细了解 Realtime Database 和 Cloud Firestore 在结算方面的差异。

最佳做法的实际运用

以下示例反映了您在数据库之间迁移数据时可能会考虑的一些注意事项。相比您使用 Realtime Database 可能采用的数据结构,您可以利用浅表读取和经过改进的查询功能,获得更自然的数据结构。

我们假设有一个城市指南应用,该应用旨在帮助用户寻找世界上各个城市的知名地标。由于 Realtime Database 缺少浅表读取功能,因此您可能必须使用两个顶层节点来设置数据结构,如下所示:

// /cities/$CITY_KEY
{
  name: "New York",
  population: 8000000,
  capital: False
}

// /city-landmark/$CITY_KEY/$LANDMARK_KEY
{
  name: "Empire State Building",
  category: "Architecture"
}

Cloud Firestore 具有浅表读取功能,因此查询集合中的文档不会从子集合中提取数据。这样,您就可以在子集合中存储地标信息:

// /cities/$CITY_ID
{
  name: "New York",
  population: 8000000,
  capital: False,
  landmarks: [... subcollection ...]
}

文档的大小上限为 1 MB,因此每个城市的文档都不能过大(您应避免在文档中嵌套列表,造成文档臃肿),这也是将地标存储为子集合的另一个原因。

Cloud Firestore 的高级查询功能可减少常见访问模式造成的重复数据需求。例如,假设此城市指南应用中的某个界面显示按人口数量排序的所有首府城市。在 Realtime Database 中,实现这一点的最有效方式是维护一个单独的首府城市列表,该列表中的数据与 cities 列表中的数据会有重复,如下所示:

{
   cities: {
    // ...
   },

   capital-cities: {
     // ...
   }
}

在 Cloud Firestore 中,您可以将按照人口数量排序的首府城市列表表示为一个查询:

db.collection('cities')
    .where('capital', '==', true)
    .orderBy('population')

请详细了解 Cloud Firestore 数据模型并参阅我们的解决方案,获得更多关于如何设计 Cloud Firestore 数据库结构的提示。

保护您的数据

无论您使用的是适用于 Android、Apple 或 Web 客户端的 Cloud Firestore 安全规则,还是适用于服务器的 Identity Access Management (IAM),都要确保您在 Cloud Firestore 以及 Realtime Database 中的数据安全无虞。这两种数据库的用户身份验证都由 Firebase Authentication 处理,因此您无需在开始使用 Cloud Firestore 时更改 Firebase Authentication 的实现机制。

要考虑的主要差异

  • 移动 SDK 和 Web SDK 使用 Cloud Firestore 安全规则来保护数据,而服务器 SDK 则使用 Identity Access Management (IAM) 来保护数据。
  • Cloud Firestore 安全规则不会进行级联,除非您使用通配符。文档和集合不会以其他方式沿用规则。
  • 您不再需要单独验证数据(像在 Realtime Database 中那样)。
  • Cloud Firestore 会在执行查询之前检查规则,以确保用户对查询返回的所有数据拥有相应的访问权限。

将历史数据移动到 Cloud Firestore

将数据和安全结构映射到 Cloud Firestore 的数据和安全模型后,您便可以开始添加数据了。如果您打算在将应用从 Realtime Database 迁移到 Cloud Firestore 之后查询历史数据,请将导出的旧数据添加到新的 Cloud Firestore 数据库。如果您打算在应用中同时使用 Realtime Database 和 Cloud Firestore,则可以跳过此步骤。

为避免新数据被旧数据覆盖,您可能需要先添加历史数据。如果您同时向这两种数据库添加新数据(如下一步所述),请确保优先处理 Cloud Functions 添加到 Cloud Firestore 的新数据。

如需将历史数据迁移到 Cloud Firestore,请执行以下操作:

  1. 从 Realtime Database 导出您的数据或使用近期的备份
    1. 转到 Firebase 控制台中的 Realtime Database 部分
    2. 数据标签中选择数据库的根级节点,然后从菜单中选择导出 JSON
  2. 在 Cloud Firestore 中创建新的数据库并添加数据

    在将部分数据移动到 Cloud Firestore 时,请考虑采用以下策略:

    • 编写一个自定义脚本来迁移您的数据。由于每个数据库都有独特的需求,因此我们无法提供此脚本的模板,但我们的 Slack 频道Stack Overflow 上的 Cloud Firestore 专家可以检查您的脚本或针对您的具体情况提供建议。
    • 使用服务器 SDK(Node.js、Java、Python 或 Go)将数据直接写入 Cloud Firestore。如需了解如何设置服务器 SDK,请参阅使用入门
    • 如需加快大量数据迁移的速度,可使用批量写入操作,并在单个网络请求中发送多达 500 项操作。
    • 如需使速度保持在 Cloud Firestore 的速率限制以下,可将操作速率限制为每个集合每秒 500 次写入。

向 Cloud Firestore 添加新数据

如需保持数据库之间的数据对等性,请向两种数据库中实时添加新数据。请使用 Cloud Functions 在客户端向 Realtime Database 写入数据时触发向 Cloud Firestore 写入数据的操作。您需要确保 Cloud Firestore 优先处理来自 Cloud Functions 的新数据,而不是优先处理为进行历史数据迁移而进行的数据写入。

请创建一个函数,用于每次客户端向 Realtime Database 写入数据时,将新数据或更改的数据写入 Cloud Firestore。详细了解适用于 Cloud Functions 的 Realtime Database 触发器

将 Cloud Firestore 作为迁移后的数据的主要数据库

如果您决定将 Cloud Firestore 作为部分数据的主要数据库,请务必考虑您已设置的所有数据镜像功能,并验证您的 Cloud Firestore 安全规则。

  1. 如果您使用 Cloud Functions 来维持数据库之间的数据对等性,请务必避免在一次循环中向两种数据库重复写入数据。请将您的函数切换为只向一种数据库写入数据,或者完全移除该函数并逐步弃用在仍与 Realtime Database 绑定的应用中已迁移数据的写入功能。您在这方面的取舍取决于您自己的具体需求和用户。

  2. 验证您的数据是否得到了适当的保护。验证您的 Cloud Firestore 安全规则或 IAM 设置。