1

I have an application in android that registers sellers, which have a unique email, I am storing them in firebase. Create a rule to not allow duplicates to be added but it does not seem to work. What am I doing wrong?

{
 "rules": {
   ".read": true,
   ".write": true,
   "sellers": {
     "$seller": {
       "email": {
         ".write": "!data.exists()"
       }
     }
   }
 }
}

my method to add

 public void addSeller(Seller seller){
    HashMap<String,Seller> map= new HashMap<>() ;
    String email = seller.getEmail().replace(".",",");
    map.put(email,seler);
    database.child("sellers").setValue(map);
}
pete
  • 355
  • 3
  • 14

1 Answers1

3

You're calling push(), which generates a new child that is statistically guaranteed to be unique.

If you want to ensure unique email addresses, you will have to keep a collection where the (encoded) email addresses are the keys:

emails
  pete@somedomain,com
  puf@somedomain,com

With this structure, the following rule will work to ensure an email address can only be written once:

{
 "rules": {
   ".read": true,
   "emails": {
     "$email": {
       ".write": "!data.exists()"
     }
   }
 }
}

The topic of unique values comes up regularly, so I recommend you also check out these:

Faruk
  • 5,438
  • 3
  • 30
  • 46
Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
  • As I understand you then I must create a child that is called emails? – pete May 26 '17 at 15:12
  • The name of the collection isn't important, there is nothing magical about it. The important thing is that in this collection you use the (encoded) email addresses as keys. And since keys are guaranteed to be unique in a collection, this ensures each email address can exist only once. – Frank van Puffelen May 26 '17 at 15:17
  • I already understand what you want to tell me but if the push is the one that generates my key automatically as I should do it manual? – pete May 26 '17 at 15:49
  • is it okay to put `".write":true` ? as it mentions in https://firebase.google.com/docs/reference/security/database/#write that it will allow writing to any descendants of that location, even if the descendants have their own `.write` rules which fail – Faruk May 26 '17 at 16:21
  • Good point @faruk. I'd completely missed that in the original rules and simply copied it over. Pete: your top-level `".write": true` rule grants all users write access to all data. Lower-level rules cannot take such permission away. – Frank van Puffelen May 26 '17 at 16:42
  • I am already using emai addresses as a key but using set value my previous data is deleted. And I found this answer but something seems to be missing in it https://stackoverflow.com/questions/37031222/firebase-add-new-child-with-specified-name – pete May 26 '17 at 19:36
  • The code you shared so far calls `push()` to add children, which will generate a unique ID. If you're using email addresses already, please add that code to the question. – Frank van Puffelen May 26 '17 at 20:52
  • Your new `addSeller` indeed now adds the seller under their encoded email address. What's the problem? Any error messages? Did you change the rules as in my answer? – Frank van Puffelen May 27 '17 at 15:10
  • My problem is that when trying to add a seller delete the previously added – pete May 27 '17 at 16:45
  • Call `updateChildren (map)` instead of `setValue(map)`: https://firebase.google.com/docs/database/android/read-and-write#update_specific_fields – Frank van Puffelen May 27 '17 at 16:53
  • @FrankvanPuffelen what can i do to ensure unique value if that string is big say 50 to 2000 characters . Can I make that string as key? what will be the best solution? – Sunny May 29 '18 at 18:54
  • ok I got an idea i can hash the value of that string and use it as a key – Sunny May 29 '18 at 19:10