Firebase:如何以原子方式更新多个资源?

时间:2013-07-03 00:01:17

标签: firebase

Firebase允许更新资源transactionally。据我了解,客户端这样做就是向服务器发送请求“如果旧值是X,则使新值为Y”。如果存在争用,则服务器可以拒绝来自客户端的多个更新,直到接受一个更新。

现在,如果我想原子更新多个资源怎么办?

如果接受第一次更新会发生什么,然后在接受第二次更新之前断开客户端连接。有没有办法在原子事务中包含多个更新?如果没有,是否有这个问题的惯用解决方案?

1 个答案:

答案 0 :(得分:44)

<强>更新

现在可以原子地更新多个位置。有关详细信息,请参阅this blog post

var mergedUpdate = {};
mergedUpdate[ 'users/' + userId + '/widgets/' + widgetId ] = true;
mergedUpdate[ 'widgets/' + widgetId ] = widgetData;

var ref = new Firebase("https://<YOUR-FIREBASE-APP>.firebaseio.com/");
ref.update(mergedUpdate);

这不会强制执行事务数据(如果值当前为X,则将其设为Y),但此部分可以移动到security rules。例如,如果我们想要同时更新两个计数器,我们可以按如下方式添加规则:

{
  "counter1": {
     ".validate": "newData.val() === (data.val()||0)+1"
  },

  "counter2"1 {
     ".validate": "newData.val() === (data.val()||0)+1"
  }
}

现在我们可以尝试与上面相同的多路径更新。如果自上次从服务器读取值以来值已更改,则尝试将失败。我们可以检查if( error.code === 'PERMISSION_DENIED' ) { ... }以查看失败是否是由验证引起的,并相应地重试。

原始帖子

执行此操作的唯一方法是在共同祖先上运行事务。

例如,如果要更新/ a / b / c和/ a / x / y,可以在/ a运行事务并更改这两个值。

这种方法的缺点是网络I / O可能会很昂贵,因为事务中的所有数据都需要下载然后发送回服务器。

您可能需要考虑的更复杂但可能更强大的方法是重构数据,以便存储编辑历史记录而不是存储实际值。例如,如果您要存储银行余额信息,则可以存储存款和取款历史记录。然后,当您想要获得余额时,您将回放整个历史记录并计算最终余额。

这种方法的优点在于它可以让你进行原子更新。例如,如果您将资金从accountA转移到accountB,您只需在日志末尾添加一个元素,说“从帐户A转帐到帐户B N美元”。附加单个元素是原子操作。

这是我们采用Firepad协作文本编辑器的方法。