在Firestore中允许更新单个字段

22

我希望让一个用户有权更新文档。但是,只有当用户更新此文档的一个特定字段时才允许更新。此用户不应更改其他字段。

在 firestore 中是否可能实现这一点?

我尝试了类似于以下内容:

function isUpdateToOpenField(attr) {
    return attr == get(/databases/$(database)/documents/stores/$(store)).data.open;
}

allow update: if isUpdateToOpenField(request.resource.data);

但我不知道如何比较更新是否对应正确的字段。

6个回答

42

规则语言中引入了地图差异以解决这个问题:

function isUpdateToOpenField() {
    return request.resource.data.diff(resource.data).affectedKeys().hasOnly(['open']);
}

allow update: if isUpdateToOpenField();

你正在将 attr 传递给函数,但从未使用它。 - AvielNiego
2
现在你的函数不接收任何参数,但你却发送了 request.resource.data :) - AvielNiego
function isUpdateSpecificFieldOnly(fieldName) { return request.resource.data.diff(resource.data).affectedKeys().hasOnly([fieldName]); } 函数isUpdateSpecificFieldOnly(fieldName) { 返回request.resource.data.diff(resource.data).affectedKeys().hasOnly([fieldName]); } - MadMac

24

更新:现在您可以使用Map.diff()而不是writeFields

检查writeFields变量以进行安全规则:

allow update: if ((request.writeFields.size() == 1) && ('open' in request.writeFields));

写嵌套字段的 writeFields 是什么样子的,例如 >> update("foo.bar", baz)?谢谢。 - lenhuy2106
@lenhuy2106:这个 && ('foo.bar' in request.writeFields) 的效果符合预期。 - Pascal

6

您可以使用:

allow update: if request.resource.data.diff(resource.data).affectedKeys().hasOnly(["fieldToBeUpdated"]);

或者

allow update: if request.resource.data.diff(resource.data).affectedKeys() == ["fieldToBeUpdated"].toSet;

根据您的用例,您可以使用 addedKeys()removedKeys() 或者 changedKeys() 来替换 affectedKeys()

正如其名称所示,affectedKeys() 相当于同时使用这三个方法。

更多详细信息请参阅此处的文档:https://firebase.google.com/docs/reference/rules/rules.MapDiff


5

由于writeFields已被弃用,不应再使用它,因此您需要检查request.resource.data。但是,它始终包含编写文档的所有字段(它的最终状态)。这意味着您将需要将编写文档的所有字段与原始文档中的resource.data中的字段进行比较,以确保只允许更改了的字段。

目前,这需要对可能编写的每个字段进行显式检查,这不是很容易实现。Firebase团队正在研究使这种规则更易于表达的方法,例如允许您区分“之前”和“之后”文档的数据映射。


1
这里有一篇有用的文章,讨论了这种策略。对于更复杂的断言,它可能会非常痛苦。希望这个问题能够尽快得到解决。 - ctrlplusb
2
嗨,关于这个话题有任何更新吗?谢谢。 - nibbana

4

由于request.resource.data会在写入之后显示未来对象-唯一的方法是使用以下方式检查每个字段:

   function notUpdating(field) {
     return !(field in request.resource.data)
      || resource.data[field] == request.resource.data[field]
   }

   allow update: if notUpdating('title') && notUpdating('description')

确认用户不能更新所有字段,除了您想让他访问的字段


1

与“Scott Crossen”的回答基本相同,稍作修改,使其更加通用

function isUpdateToOpenField(attr) {
    return request.resource.data.diff(resource.data).affectedKeys().hasOnly([attr]);
}

allow update: if isUpdateToOpenField('open');


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接