Firestore Rules to restrict write access to a specific field in a document
I believe something along the following would work, it allows clients to update fields except for charge, as well as create documents that don't have the charge field.
service cloud.firestore {
match /databases/{database}/documents {
function valid_create() {
return !(request.resource.data.keys().hasAll(["charge"]));
}
function valid_update() {
return request.resource.data.charge == resource.data.charge
|| (valid_create()
&& !(resource.data.keys().hasAll(["charge"])))
}
match /payments/{userId} {
allow read: if request.auth.uid == userId;
allow create: if request.auth.uid == userId
&& valid_create();
allow update: if request.auth.uid == userId
&& valid_update();
}
}
}
The accepted answer does not work on update
, in which request.resource.data
returns a new map that's already merged with existing data. Because of that, request.resource.data.keys().hasAll([<<field>>])
always return true
.
Regardless, what works for me is using .diff()
:
function meta_is_modified() {
return 'meta' in resource.data.diff(request.resource.data).affectedKeys();
}
Here's another version with multiple protected fields:
function invalid_modification() {
return resource.data.diff(request.resource.data).affectedKeys().hasAny(['field1', 'field2'].toSet());
}
Set type was announced, along with some other cool stuff.
Using Sets to ensure that a document only has fields "a", "b", and "c":
request.resource.data.keys().toSet() == ["a", "b", "c"].toSet()
Similarly, you could make sure that a document only has specified keys, but not others:
(request.resource.data.keys().toSet() - ["required","and","opt","keys"].toSet()).size == 0?`