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

时间:2015-07-30 10:22:57

标签: firebase firebase-security

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

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

我可以获取引用的快照并在修补之前检查它,但我希望有一种更优雅的方法来实现它而不使用两个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)

鉴于我的应用程序的设计,如果请求条目仍然存在,我只想执行该修补程序。很明显,我可以在修补之前获得快照并执行检查,但这对我来说似乎很尴尬。

1 个答案:

答案 0 :(得分:4)

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

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

因此,您必须在应用程序中创建这种区别。

您有几个选择。并非所有这些都适用于REST API,但无论如何我都会提及它们。

交易更新

Firebase SDK(适用于JavaScript,Java / Android和iOS / OSX)有一个名为transaction的方法,可让您运行比较和设置操作。

通过该操作,您可以

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属性。所以您也可以简单地将记录节点作为标记,但删除所有其属性:

requests:
    rq123: true

由于Firebase删除了没有值的节点,因此我将true作为值添加到此处。

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

".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()"

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