For the life of me, I cannot understand why the following is resulting in a false for allowing writes. Assume my users collection is empty to start
Here's a function that doesn't trigger security rule errors like "Property name is undefined on object".
Features/properties:
function notUpdated(key) {
return !(key in request.resource.data)
|| (
(key in resource.data)
&& request.resource.data[key] == resource.data[key]
);
}
Explanation
1: If the field isn't present on request.resource.data, it means that the field isn't present on the request nor on the existing resource. (Remember that request.resource.data represents the resource after a successful write operation, i.e. the "future" document.) If the field doesn't exist anywhere, allow the write.
2: If the field does exist on either the incoming resource or the existing resource, we need to do another check. First, check if the field is present on the existing resource. If it doesn't, the update is denied. If it does, continue to check if the request field is equal to the existing field. If they're equal, allow the write. At this point it's impossible for request.resource.data[field] to trigger a reference error; if the field is present on resource.data, it's present on request.resource.data as well.