'Array comparison in Firestore security rules

A user needs to be able to add their uid to an array called 'users', within a document. They should only be able to add/remove their uid, and nothing else.

I need to write a security rule to allow for this, but can't figure out how to do array comparison in the security rules.

It needs to be something like this:

allow update: if request.resource.data.users == [...resource.data.users, request.auth.uid]

This is the query:

.update({
      users: firebase.firestore.FieldValue.arrayUnion(params.uid),
    })

Is this possible?



Solution 1:[1]

Yes, it's possible,:

allow update: if request.auth != null 
&& request.auth.uid in request.resource.data.users
&& request.resource.data.users.size() - resource.data.users.size() == 1

request.resource.data.users is the state of the users document AFTER the proposed change and resource.data.users is the state of the document BEFORE the proposed change. By checking if the difference is one, you guarantee that only one item was added to the array.

Solution 2:[2]

Yes. It is possible to check if a particular uid is present in an array field of the document in the security rules. You can use in condition to check the same.

So it would look a lot like this.

allow update: if (request.auth.uid in request.resource.data.users);

Hope this helps.

Solution 3:[3]

There's a removeAll method on arrays for array exclusion. See this answer

Here's a little function checking that two arrays differ exactly by the provided element.

function arrDifferBy(arr1, arr2, el) {
            let diff12 = arr1.removeAll(arr2);
            let diff21 = arr2.removeAll(arr1);
            return diff12.length == 1 && diff21.length == 0 && diff12[0] == el || 
                diff12.length == 0 && diff21.length == 1 && diff21[0] == el
}

In your case it would be used like

allow update: if arrDifferBy(request.resource.data.users, resource.data.users, request.auth.uid)

Edit: after a few hours of battling with a similar task myself I've decided to do it in a cloud function. If this depends on a creation of some other document, or you can use callable cloud functions, it's much less hassle.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Mohsen Zoofan
Solution 2 denniskbijo
Solution 3