Firestore rule to only add/remove one item of array

Viewed 314

To optimize usage, I have a Firestore collection with only one document, consisting in a single field, which is an array of strings.

This is what the data looks like in the collection. Just one document with one field, which is an array: enter image description here

On the client side, the app is simply retrieving the entire status document, picking one at random, and then sending the entire array back minus the one it picked

var all = await metaRef.doc("status").get();
List tokens=all['all'];
var r=new Random();
int numar=r.nextInt(tokens.length);
var ales=tokens[numar];
tokens.removeAt(numar);
metaRef.doc("status").set({"all":tokens});

Then it tries to do some stuff with the string, which may fail or succeed. If it succeeds, then no more writing to the database, but if it fails it fetches that array again, adds the string back and pushes it:

var all = await metaRef.doc("status").get();
List tokens=all['all'];
List<String> toate=(tokens.map((element) => element as String).toList());
toate.add(ales.toString());
metaRef.doc("status").set({"all":toate});
2 Answers

You can use the methods associated with the Set object.

Here is an example to check that only 1 item was removed:

allow update: if checkremoveonlyoneitem()

function checkremoveonlyoneitem() {
  let set = resource.data.array.toSet();
  let setafter = request.resource.data.array.toSet();
  return set.size() == setafter.size() + 1
    && set.intersection(setafter).size() == 1;
}

Then you can check that only one item was added. And you should also add additional checks in case the array does not exist on your doc.

If you are not sure about how the app performs the task i.e., successfully or not, then I guess it is nice idea to implement this logic in the client code. You can just make a simple conditional block which deletes the field from the document if the operation succeeds, either due to offline condition or any other issue. You can find the following sample from the following document regarding how to do it. Like this, with just one write you can delete the field which the user picks without updating the whole document.

city_ref = db.collection(u'cities').document(u'BJ')
city_ref.update({
    u'capital': firestore.DELETE_FIELD
})snippets.py

Related