CaHa
CaHa

Reputation: 1166

Reference field in nested map in Firestore security rules

I have this data structure:

enter image description here

and need a rule that only allows updates when the city attribute is not changed:

match /requests/{requestId} {
  allow update: if (request.resource.data.diff(resource.data).unchangedKeys().
     hasAll(["customerlocation.city"]))

That doesn't work, because the diff result only shows the customerlocation field, but not the city attribute.

Is it even possible to achieve what I want? I know there are limitations wrt what you can do with nested objects in security rules, but I have might just missed something.

Upvotes: 4

Views: 657

Answers (4)

nitroplr
nitroplr

Reputation: 109

I think what you're after is something like this:

match /requests/{requestId} {
  allow update: if (request.resource.data.customerLocation.diff(resource.data.customerLocation).unchangedKeys().
     hasAll([resource.data.customerlocation.city]))

I am unsure about the [resource.data.customerlocation.city] part...but I did just write a similar rule to prevent updates to a map field that is not the user's own id that works.

allow update: if isSignedIn() && (request.resource.data.memberMap.diff(resource.data.memberMap).affectedKeys().hasOnly([getUid()]));

Upvotes: 0

nVitius
nVitius

Reputation: 2224

I believe that the solution Aion proposed is the only one that will work if you don't want to change your data structure and have to do this inside of the Firestore rules.

I don't know what your overall data structure looks like, but you could move customerLocation out to its own collection. Then you would store a DocumentReference to customerLocation inside of the request.

You could also create a cloud function with document('requests/{requestId}').onUpdate() and check if the city changed. If it has, then change it back in there. This would require you to keep track of the fact that you changed back the property though. Otherwise, the function would keep triggering and flipping the values.

Upvotes: 2

EJZ
EJZ

Reputation: 1256

I would simply recommend that you check to see if the City is still in it's default value, in this example I put that as "Default City" (that default would likely be nil)

match /requests/{requestID} {
  allow update: if request.resource.customerLocation.city == "Default City"
}

Since your entire Firestore database is not referenced it may look slightly different in your project, but I think logically this will work.

Upvotes: 0

Aion
Aion

Reputation: 681

Why dont you directly compare the field value ?

allow update: if request.resource.data.customerLocation.city
 != resource.data.customerLocation.city;

Upvotes: 1

Related Questions