如何防止更新不存在的节点?

How do I prevent updates to nonexistent nodes?

我正在使用 REST api 来修补我的 Firebase 商店中的节点。我想阻止更新不存在的节点(因为它们之前已被删除)。现在,对不存在的引用执行 PATCH 操作会重新创建它。

我研究了设置安全规则,但是 newData.exists() 不区分设置新值和修补,所以我不知道如何在不限制新创建的情况下允许我想要的内容。

我可以获得引用的快照并在 PATCHING 之前进行检查,但我希望有一种更优雅的方式来完成它而无需使用两个 REST 调用。

编辑:一些代码!

我的 Firebase 架构如下所示:

requests:
    rq123:
        id: '123'
        sender: '1'
        recipient: '2'
        expiration: '1234567',
        filled: false,
        filledDate: '',

新请求是从移动客户端写入的。我的服务器可以使用 REST api 更新这些请求条目。使用 python-firebase 库,看起来像:

request_ref = firebase_root + '/requests/' + request.id
patch_data = {
              'filled':'true',
              'filled_date':'7654321'
}

firebase_conn.patch(request_ref, patch_data)

考虑到我的应用程序的设计,我只想在请求条目仍然存在时执行该修补程序。很明显,我可以在修补之前获取快照并以这种方式执行检查,但这对我来说似乎很尴尬。

正如我在评论中所说,这些情况之间没有区别:

  • 正在写入不存在的数据库位置
  • 正在写入不存在的数据库位置不再

所以您必须在您的申请中做出区分。

您有几个选择。并非所有这些都适用于 REST API,但为了完整起见,我还是会提及它们。

交易更新

Firebase SDK(适用于 JavaScript、Java/Android 和 iOS/OSX)有一个名为 transaction 的方法,它允许您 运行 比较- and-set操作。

通过该操作,您可以

ref.transaction(function(current) {
  if (current) {
    current.filled: true,
    current.filled_date:'7654321'
  }
  return current;
});

但由于此方法在 REST API 上不可用,因此不适用于您的场景。

标记删除的记录

或者您可以标记已删除的记录,而不是实际删除它们:

requests:
    rq123:
        id: '123'
        sender: '1'
        recipient: '2'
        expiration: '1234567'
        filled: false
        filledDate: ''
        DELETED: true

您还可以在伪删除请求时删除所有其他属性,即

requests:
    rq123:
        DELETED: true

那么在你的安全规则中,当这个标志存在时你可以拒绝写操作:

".write": "data.child('DELETED').val() != true"

标记记录的方法有很多种。例如,在您的情况下,记录节点似乎总是有一个 id 属性。所以你也可以简单地将记录节点保留为标记,但删除 all 它的属性:

requests:
    rq123: true

由于 Firebase 删除了没有值的节点,我将 true 放在这里作为值。

使用上述结构,我们只能允许具有 id 属性(创建请求时的情况)或 id 属性 已经存在(来自 REST API 的 PATH 请求):

".write": "newData.child('id').exists() || data.child('id').exists()"

保留已删除节点的列表

我的最终方法是保留已删除请求键的列表:

requests:
    rq123:
        id: '123'
        sender: '1'
        recipient: '2'
        expiration: '1234567'
        filled: false
        filledDate: ''
deleted:
    rq456: true
    rq789: true

我们再次为已删除的节点设置一个虚拟值 true,以防止 Firebase 删除它们。

使用此结构,当您要写入的密钥存在于 deleted 请求列表中时,您可以拒绝写入操作:

".write": "!root.child('deleted').child(newData.key()).exists()"

每种方法都有其优点和缺点,因此您必须自己决定哪种方法最适合您的情况。