2

I am making batch operation from client to update only one field but while making batch operation and on testing in security rules It is observed that more than one fields are being updated. I checked this using request.resource.data.size() >1 and request.resource.data.keys().size()>1 returning true(document being updated) but this is not intended as I want to check in security rules that only one field is being updated using checks like request.resource.data.keys().hasOnly(['someFieldToUpdate']) but this is not working now, previously I remember there was writeFields to check that but it is not present now in documentation and also this answer mentions it. So how can I check the fields which are actually being updated in batch operations now ?

Kartik Watwani
  • 629
  • 8
  • 20

2 Answers2

9

You can use the new diff() method on the data map. It tells you what keys are changed. Here is a sample:

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

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

Adapted from this answer.

phatmann
  • 18,161
  • 7
  • 61
  • 51
3

The request.resource.data field contains the resource as it will exist after the write operation has succeeded. The writeFields property was removed since it could not always reliably be populated.

Right now the only option I can think of is to check if each individual field has changed, and then only allow it if there's one change. But to be honest, that sounds like an odd use-case. A more common use-case I see it to limit what specific fields the user can update, not how many they can update at once.

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
  • I do want user to update a 'specific' field and not any other field which I am checking using request.resource.data.keys().hasOnly(['someFieldToUpdate']), I gave an example about number of fields just to tell that there are more keys in request.resource.data than that actually updated from client. Now I know that request.resource.data tells about the state of document after write operation. So to sum up the only way to check whether only one specific field is updated is to check all the fields whether they have changed or not and take decision based on that. – Kartik Watwani Jan 23 '19 at 16:19
  • Indeed that is correct. You have to check for all those fields whether `request.resource.data.field == resource.data.field`. – Frank van Puffelen Jan 23 '19 at 21:34
  • 2
    That is so much of pain because that document has more than 10 fields and there are sub-objects as well, so checking of equality of sub-objects is not possible as the keys in sub-objects vary depending on some other logic. The only way which I could see is using cloud functions and reverting back to previous state if the change doesn't satisfies the condition. I miss `writeFields` :P – Kartik Watwani Jan 23 '19 at 21:43
  • 1
    @FrankvanPuffelen This is especially tough if you have a complex object. In my case I have a user document where I want user to only update the name. It has multiple maps inside it which is written to the user document by cloud functions and I don't want those maps to be updated. In security rule, I can't check for equality of maps because the keys are not fixed and values are objects. The only way for me to fix this is to write a cloud function which only takes in a name and updates the name in user doc. It would be great if I could use security rules here. – Nikhil Agarwal May 08 '19 at 08:17