Firestore rule to only allow update on value change

Solution for Firestore rule to only allow update on value change
is Given Below:

I have a function that is evaluating if an update is allowed for a user’s profile. As you can see, the validProfileUpdate function calls the validFieldUpdate function for each field I have listed (in this case name and age). When I execute an update command for just one of the fields it will work, but when I uncomment the second one (in this case, for age) it will always fail. I only want these fields to be allowed to update based on if there’s a change in data between what’s being sent in and what already exists.

function validProfileUpdate() {
  let validKeys = ['name', 'age'];

  return request.resource.data.diff(resource.data).changedKeys().hasOnly(validKeys) &&
    validFieldUpdate('name', validName()) &&
    validFieldUpdate('age', validAge());
}
function validFieldUpdate(field, condition) {
  return !(field in request.resource.data.keys()) ||
  (request.resource.data[field] != resource.data[field] && condition);
}

What I’m having difficulty with is that I figured the line !(field in request.resource.data.keys()) in validFieldUpdate would catch any fields not included in the update that’s sent and it would return true but for some reason that’s not happening when I add the second field age.

So in summary, this works and only allows updates after it’s sent for names that aren’t Joe:

const profilePayload = {
  name: 'Joe'
}

await userProfileRef.update({ ...profilePayload })

But this is blocked by the rules 100% of the time:

const profilePayload = {
  name: 'Joe'
  age: 25

}

await userProfileRef.update({ ...profilePayload })

You can use affectedKeys to compare the items rather than changedKeys as changedKeys only accounts for key values that are different from the original, a problem if the value stays the same.

  let validKeys = ['name', 'age'];
if request.resource.data.diff(resource.data).affectedKeys().hasOnly(validKeys);

Affected:

which lists any keys that have been added to, removed from or modified from the Map calling diff() compared to the Map passed to diff()

Changed:

which lists any keys that appear in both the Map calling diff() and the Map passed to diff(), but whose values are not equal.