0

I am looking for syntax to setup a rule in my Firebase Realtime DB to confirm that the value being passed from my app does not already exist in that particular location before writing another duplicate entry. I am passing an "ExponentPushToken" value for push notifications. This happens anonymously. That is, the write is happening without any user authentication, the DB is simply storing a list of "ExponentPushToken" like so:

{
  "users" : {
    "push_token" : {
      "auto-generated key" : "ExponentPushToken-value"
    }
  }
}

I attempted to use the following, but it still will allow the "duplicate" value to be written. I am wondering if this has anything to do with random 'auto-generated key' that is generated for each instance a value written to the DB, or if i am not thinking through this properly.

{
  "rules": {
    ".read": "false",
    ".write": "true && newData.val() !== data.child('push_token').val()",
  }
}

For context, each ExponentPushToken is a unique value for a given device that is used to open my app. The ExponentPushToken is a unique ID that is assigned to that device indefinitely and won't change ever in any case that particular device is accessing the app. The ExponentPushToken is assigned to the device indefinitely, and is written to the DB. Each time the app is opened, there is a push/set command to write that token to the DB within my app's code. I would like to setup a rule for Firebase Realtime DB to confirm the value being passed from the app to the DB does NOT get written if that value already exists. I am stuck and am finding myself having to manually parse the db to remove duplicate value to keep the DB clean and not send more than one Push Notification to app users.

Any help or direction you can provide would be greatly appreciated!

Thanks!

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807

2 Answers2

1

This cannot be done using firebase security rules, as they cannot search for values (that wouldn't scale). The query to check for existing values in a particular location in the database would have to be done in the app that is performing the push/writing of the value into the database.

The app would need to query the database for values and have a condition in place to prevent the writing of duplicate values.

An example of working code that can be implemented within the app can be found here that accomplishes the desired outcome for this specific ask/desired outcome.

Expo and Firebase Realtime DB - Read values and confirm a particular value does not exist before writing to database

0

Rules are evaluated in the context of the node/path in which you declare them. So the .write rule in your question is evaluated on the root, and both data and newData contain the data/new data at the root.

The easiest way to verify that there's no data at the path, is to define this rules at that path:

{
  "rules": {
    ".read": "false",
    "push_token": {
      "$pushId": {
        ".write": "!data.exists()",
      }
    }
  }
}

The $pusId here means that the rules under there are applies to every child node of push_token, which seems to match your JSON. For more on this, see the documentation on wildcard variables.

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
  • Thanks for the response! For clarity, I am not looking to write where no data (or no "values") exists. I am hoping to write data, only in the event that the data (a particular value) being written doesn't already exist in that location. Does that make sense? – Mark-The-Guitar-Guy Aug 20 '21 at 03:49
  • I'm not sure I understand. But did you try my rules against that requirement? And if so, can you show the code that performs a write that you want to disallow, or vice versa? – Frank van Puffelen Aug 20 '21 at 04:09
  • Here is the process (example): User opens app on device. App writes ExpoPushToken = 123 to Firebase Realtime DB in location referenced above. Same user opens app again at a later time, and app writes ExpoPushToken = 123 again. My goal is to setup a rule in the DB to prevent that duplicate entry. That is, search DB for value = 123, if that value already exists in the DB i want to prevent the write to DB, if value does NOT exist, proceed with the write to DB. Does that make sense? I can add the js code performing the write from within my app if that'd be helpful...? – Mark-The-Guitar-Guy Aug 21 '21 at 17:09
  • I think I understand now. So you want the **value** to be unique in the database? That is not possible in security rules, as they can't search for values (that wouldn't scale). To make something unique, it'll have to be the key of a node (so your rules can directly look it up). We've covered this a few times before, so I recommend checking https://stackoverflow.com/search?q=%5Bfirebase-realtime-database%5D+unique+value, like https://stackoverflow.com/a/39151205 and https://stackoverflow.com/a/25328654 – Frank van Puffelen Aug 21 '21 at 17:19
  • Hey @Frank van Puffelen I am currently writing to the database with unique 'keys' as the key is being auto-generated. I need to be able to vet and cancel the writing of a new 'row' to the database (that is a new key and value) in the event the value already exists. If that cannot be done in Firebase Realtime DB rules, is this something that can be done using js in my app? I am looking for ANY solution to ensure that writing the same value each time a user open my app is not taking place. – Mark-The-Guitar-Guy Sep 14 '21 at 17:17
  • There is no secure way to prevent duplicate *values*. To ensure something is unique, it has to be the key in the database. The questions I linked show how to implement that. – Frank van Puffelen Sep 14 '21 at 18:25
  • is there a not so secure way to prevent duplicate values? Is there any way to query the real time DB values, before writing? Again the DB structure is incredibly basic. Just querying one column. Thats it. There not multiple nodes to query across, one singular node. Anything that could be done? Either in Firebase or my app? – Mark-The-Guitar-Guy Nov 16 '21 at 19:01
  • There is no secure way to prevent duplicate **values**. ¯\_(ツ)_/¯ – Frank van Puffelen Nov 17 '21 at 20:55
  • is there a non-secure way to do so? – Mark-The-Guitar-Guy Nov 21 '21 at 05:42
  • do you think you might have an idea on how I can write my function so that it queries to see if the value exists before writing to the db in my app? Here is what i have written now, which writes to the db no matter what: `const token = (await Notifications.getExpoPushTokenAsync()).data; console.log(token); var userListRef = firebase.database().ref("users/push_token"); var newUserRef = userListRef.push(); newUserRef.set(token);` – Mark-The-Guitar-Guy Jan 29 '22 at 04:01