1

I have a small Firebase DB, I need to check if a value of node exits

I add a child with

childByAutoId()

so my DB is like this

(randomID is a random Number generated from firebase)

numbers:
---"randomID": "stringSavedFromMyCode"
---"randinID": "stringSavedFromMyCode"

Do you know how I can do it in a simple way to verify it?

If the "stringSavedFromMyCode" (string indicating the Swift code) is equal to a value present on the DB, it must not be set to .setValue on Firebase

I don't know if I'm well explained

Thanks

EDIT:

before I used to

ref.child("numbers").childByAutoId().setValue(stringSavedFromMyCode)
nonickname
  • 181
  • 1
  • 3
  • 10

1 Answers1

1

If I understand correctly you want to write a value to the database if it doesn't exist yet.


With your current data structure that is hard to do, because there is no way on the database server to prevent multiple occurrences of the same value. So while you can do this on the client:

  1. run a query for the value, with something like ref.child("numbers").queryOrderedByValue().queryEqualToValue("stringSavedFromMyCode")queryLimited(toFirst: 1)
  2. Check if the query has any results
  3. If not, write a new node with the value.

This may work most of the time, but has an inherent race condition between step 1 and step 3. To remove that race condition you'll need to use a transaction, which unfortunately will have to run on the entire numbers node in your current data structure.


A better solution is to change your data structure.

If you want something to be unique within a certain scope in Firebase, you should use that as the key of the nodes under that scopes. So if you want to store unique numbers, use the actual numbers as the keys under numbers:

numbers:
---"stringSavedFromMyCode": true
---"string2SavedFromMyCode": true

Given that Firebase stores the data as JSON, the above structure guarantees that each stringSavedFromMyCode can only occur once under numbers. Duplicates are impossible on the data structure level.

So the last line from your question would roughly translate to:

ref.child("numbers").child(stringSavedFromMyCode).setValue(true)

But to ensure that you only write when it doesn't exists, you'll need to still use a transaction:

  1. Run a transaction on ref.child("numbers").child("stringSavedFromMyCode").
  2. If currentData.value is nil.
  3. If it is, set the new value to currentData.

This runs a transaction at just the node you're trying to write. Because of this, it can also be enforced on the server with Firebase's security rules. They'd look something like this:

{
  "rules": {
    "numbers": {
      "$number": {
        ".write": "!data.exists()"
      }
    }
  }
}

These rules basically say: "you can write a node under number if it doesn't exist yet". But I definitely recommend reading the full documentation on security rules, as they're a key component of modeling and securing data in Firebase.


Also see:

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
  • I edited the question, how can I get that unique structure on firebase by changing the setValue? in the swift code I won't have to do anything (will the firebase rules do it?) thanks – nonickname Mar 14 '20 at 15:04
  • t worked with a single line of code. Perfect. The rules are not served (even though I saved them equally). Thanks so much – nonickname Mar 14 '20 at 15:48
  • Good to hear you got it working. Be sure to look at the transaction logic, as that is needed to prevent race conditions (as are the security rules) – Frank van Puffelen Mar 14 '20 at 16:05