【问题标题】:How to handle required relationships in Firebase Realtime Database?如何在 Firebase 实时数据库中处理所需的关系?
【发布时间】:2021-11-15 19:35:20
【问题描述】:

本地 SQL

在我的应用程序本地,我有数据模型 FooBar,每个都存储在单独的 SQL 表中。

Foo 通过 id 引用 Bar,如果 Foo 没有对应的 Bar 是错误的。

有时它们会一起显示,有时一次只显示一个,并且可以编辑一个而不影响另一个。

Firebase 实时数据库

我现在正在研究如何最好地将它集成到我的应用程序中,以确保顺畅的同步和备份体验。一切都非常简单。 但我不知道如何确保上述合同保持真实。

会有 Foo 同步的情况;并且 Bar 仅在稍后的某个时间同步(考虑一个简单的网络连接断开)。在此期间,该特定用户的实时数据库将被视为处于非法状态。当连接恢复时, Foo 和 Bar 最终将同步并且整个事情可以继续流动 - 但在那之前我该怎么办?我该如何防范呢?我需要,还是在所有错误的地方寻找答案?

我一直在探索的一些想法:

  • 允许在本地缺少 Bar。考虑 Foo 在其 bar 丢失时处于部分状态,例如在“准备就绪”之前,它可能会隐藏在 UI 中。
  • 以某种方式在本地组合 Foo 和 Bar,仅在其 Bar 可用时才保存 Foo,等等。
  • 在 Foo 内嵌套 Bar 以便它们始终同步在一起。 (这似乎很麻烦,我的应用程序中有几个关系,例如 Foo->Bar,如果这是处理它的“正确”方式,我必须将 Bar 嵌套在所有这些关系中)

如果可以,请赐教。 Firebase 对我来说并不陌生,但是将这种复杂的数据与多种关系同步却是。

附加上下文

虽然我无法分享实际的 Foo & Bar,但我有一个我认为与挑战非常相似的示例。

考虑一个包含消息、房间和用户的聊天应用程序。

您可以向房间发布消息,还可以编辑房间名称和颜色。没有用户和房间,消息就无法存在。从同步的角度来看,用户、房间和消息现在必须“一起”同步(或者至少,如果没有其他消息通过,消息将是无效的)。

使用多路径更新来处理这个问题,我会在每次发布/编辑消息时更新所有 3 个。我是否正确理解了这一点?如果是这样,那将意味着在我自己的场景中更新 1+N+N 个节点。 N+N 个节点不会有任何实际更新的数据,但会包含在更新中以确保所有数据同步在一起。

进一步明确

首先,回到问题的根源 - Foo 在本地通过其 id 引用 Bar。如果我的应用程序最终处于一个没有另一个存在的状态,它会在几乎所有地方引起问题(这就是我所说的非法状态,它不可能发生)。

考虑到防范它的方法,我被建议在 firebase 中使用多路径更新(我相信这与扇出相似/相同?)。我会尽快尝试这种方法,尽管我对此感到保留,只是为了验证我的感受是否只是缺乏经验。

我很难理解这样一个事实,即如果 Foo 在本地发生变化,它现在也会导致对 Bar 的查询,这样两者就可以一起同步到 firebase。对于这样一个简单的场景,这听起来不错,但在实践中,这意味着:您对 X 进行编辑并保存在本地,此后不久将同步到 firebase,现在 Y 和 Z 为 100:s也被查询,并在同一操作中插入到 firebase。此时 Y 和 Z 可能已经在 firebase 中保持最新状态,并且它们没有在本地更改。

当涉及到 firebase 时,我对这类场景没有太多经验,我的想法是这样的做法是对资源的巨大浪费 - 我确信 firebase 在本地做了很多工作,因此不会发生不必要的同步工作对于实际上没有改变的数据,但我无法摆脱这样的想法,即我仍然会在本地查询 100:s 和 100:s 的复杂模型很多,如果它没有似乎 是必要的(在我从另一个角度解决问题的情况下,肯定存在另一种方法吗?)。

【问题讨论】:

  • 这个问题有点模糊,使用的一些语言不清楚。例如; Firebase 有事务,其中数据写入必须全部成功,否则全部失败。因此,当首次编写 Foo 和 Bar 时,将在事务中完成 - 这保证它们都存在,这将消除对象“丢失”的可能性(无论丢失意味着什么)。 “非法状态”是什么意思?如果 Firebase 中同时存在 Foo 和 Bar,并且 bar 在离线时被编辑,则当应用在线时,这些更改会同步并更新 Bar。或许你可以提供一个更具体的例子?
  • 我在帖子中添加了一些“更清晰”的内容 - 希望现在更有意义。虽然事务有助于确保 Foo 和 Bar 同步成功或失败,但它仍然需要我执行所有这些查询(在我的帖子中有更多内容)。
  • 不幸的是仍然很模糊。您说的是没有另一个存在并且具有事务性写入,这是不可能发生的。当 foo 和 bar 第一次被写入时,它将在保证它们都存在的写入事务中完成,因此一个没有另一个 - 是不可能的 -。此外,这个 *Foo 在本地通过其 id 引用 Bar。*` 在 Firebase 中不是一个概念;它是第一个在线数据库,并且在本地与在线引用某些内容“不是您可以做的”
  • 另外,Firebase 不是关系数据库,因此 如果 Foo 在本地更改,现在也会导致发生 Bar 的查询 是不可能发生的事情。您可以查询 Foo 或更改 foo ,但这与 Bar 没有任何关系。例如您可以整天更新 Foo ,但这与查询 Bar 无关,因为它们不相关(因为如上所述,Firebase 不是关系数据库)。更具体的东西可能会帮助我们理解这个难题,但同样,Foo 和 Bar 是完全独立的数据片段,没有自动关系。
  • 我所说的关系都是本地的(SQL);更新 Foo 导致查询 Bar 也是本地的,因为 Id 需要将 Bar 包含在我对 firebase 的更新中 Id 也需要在本地获取它。我确实缓存了,但是在我的场景中查询“Bar”实际上是来自不同表的 10 个查询,因此感觉非常无效。如果还有其他像扇出这样的“技术”,我很想知道;但我会给它一个诚实的机会。

标签: firebase firebase-realtime-database


【解决方案1】:

会有 Foo 同步的情况;并且 Bar 仅在稍后的某个时间同步(考虑一个简单的网络连接中断)。

如果两个写入来自同一个客户端,请考虑使用using multi-path updates 来防止此类部分更新。

【讨论】:

  • 为了我正确理解你,这样做就像在一个事务中编写 Foo & Bar - 没有明确地将 Bar 作为 Foo 的嵌套值包含?
  • 是的。我建议试一试。如果您仍然遇到困难,我建议您发布一个具体的代码示例 - 因为没有它(至少对我而言)很难推理 Foo 和 Bar。
  • 我在我的问题中包含了一些额外的上下文,请看一下!在考虑每次更改看似很小的东西时实际会移动多少数据时,我有点挣扎。
  • 嘿@zoltish:这里有什么更新吗?
  • @FrankvanPuffelen OP 正在使用 SQL 在本地存储他们的数据,同步问题与使用 Firebase 的关系更大。 我所指的关系都是本地的(SQL);更新 Foo 导致对 Bar 的查询也是本地的,因为 Id 需要在我对 Firebase 的更新中包含 Bar Id 也需要在本地获取它
【解决方案2】:

我终于设法解决了这个问题,希望这可以帮助其他遇到同样挑战的人!

首先,在DatabaseReference 上注册ChildEventListener 时;我会收到一份包含最新数据版本的通知,然后每次数据更改时都会收到通知。

使用它,我按数据的“版本”(基本上是编辑时间的时间戳)过滤数据,以便实际处理比最新本地版本更新的数据。

任何时候Foo 出现而其Bar 对应对象尚未到达,我会将其标记为延迟任务,应在下一次同步操作完成后重试 - 在几乎所有情况下,Bar 都会出现通过Foo 之后,该任务将在下一次重试时成功。在某些情况下,Bar 之前会执行一些其他同步操作,但我的重试逻辑都是本地的并且很便宜,所以我不介意。

如果在应用程序的此生命周期内没有出现Bar,这不是问题,因为最新版本的Foo 将在下次启动应用程序时出现,并且循环只会重复自身直到@987654330 @ & Bar 可用,此时它们被插入到我的本地数据库中。

我不知道这是否是解决它的“正确”方法。但是根据我的知识,这是我能想到的最好的方法,而且我看不出它有任何真正的缺点。随意在 cmets 中批评它,或者如果您认为您有更好的解决方案,请提供另一个答案!

谢谢。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-12-12
    • 2017-01-12
    • 2018-04-07
    • 2020-02-01
    • 2021-04-10
    • 2018-05-24
    • 2013-01-23
    • 1970-01-01
    相关资源
    最近更新 更多