Robin Manoli Robin Manoli - 8 months ago 52
JSON Question

Firebase rule allowing children to be deleted only one by one

Consider the following firebase database rules for users. I wonder if there is a way to write a rule that can delete children (friends) one by one, but not all at once?

Here a simple delete operation will not work, because friends needs to either have been empty or have children. However, it can be updated to have any other children whatsoever, meaning all children can be overwritten at once.

/* user can read all user data */
".read": "$uid == auth.uid",
/* allow to add to friends but not delete */
".write": "$uid == auth.uid && (!data.child('friends').exists() || newData.child('friends').hasChildren())",
/* other user data also needs to be writable */
"name": {},
/* only explicit user data is allowed */
"$other": { ".validate": false },
"$friend_uid": { ".validate": "root.child('user').child($friend_uid).exists()" },

Answer Source

The solution to this is to make sure the friends child is not changed when its parent is written. This means that children that are allowed to be overwritten in bulk can be, but friends is only writable when accessed as a child.

This means the .write rule is changed to:

".write": "$uid == auth.uid && data.child('friends').val() == newData.child('friends').val()",

and the friends rule is changed from .validate (as it's not concerned with deletes) to .write, using the same auth policy as before.

"$friend_uid": { ".write": "$uid == auth.uid" },

(According to firebase policy, .write policies are inherited by children, so the most straight forward solution would be to move the .write rules to each child. The problem with that however is that it seems to allow only to write each child at a time.)