0

I've Firebase Database where each user has own email and username. How to check unique username? I tried to make it like this, but my code doesn't work properly therefore different users can have the same username

  usernameField.isHidden = false
    let username:String = self.usernameField.text!

    if (usernameField.text?.isEmpty == false){
    ref.child("users").queryOrdered(byChild("username").queryEqual(toValue: username).observeSingleEvent(of: .value, with: { snapshot in

            if snapshot.exists(){

                print("username exist")

            }else{

                ref.root.child("users").child(userID).updateChildValues(["username": username])
            }

        })
}

enter image description here

I'm a little bit newbie in Firebase I store email and username for each user like this newUserReference.setValue(["username":String(), "email" : self.emailTextField.text!]). On next view, user can type username in usernameField.text and this value will be added in Firebase Database. But if the next user (user 2) will type the same username like previous user, it must be blocked, because username should be unique

Diana
  • 683
  • 1
  • 8
  • 17

2 Answers2

1

If you're trying to store your user's id on login do this when you receive a successful response to the login:

create a Shared Instance to store the ID

class userDataSource {
    var id : String? // variable to store your users ID
    static let sharedInstance = PageDataSource() // global access to this dataSource
    private init() {}
}

Assign the id a value after successful login

func getIDFromLogin() {
    if let user = Auth.auth().currentUser {
        print(user.uid)
        userDataSource.sharedInstance.id = user.uid
    }
}

Then you can do this to view each id:

 ref.child("users").observeSingleEvent(of: .value, with: { snapshot in
     if let snapshots = snapshot.children.allObjects as? [DataSnapshot] { 
         for snap in snapshots {
             print(snap.key) // you can compare userDataSource.sharedInstance.id to this value
         } 
     }     
 })

Or if you just want that user's data do this:

ref.child("users").child(userDataSource.sharedInstance.id!).observeSingleEvent(of: .value, with: { snapshot in
     if let snapshots = snapshot.children.allObjects as? [DataSnapshot] { 
             for snap in snapshots {
                 print(snap) 
         } 
     }     
 })

Edit to answer your question more accurately

Here is an answer more inline with your question. First thing I will recommend is for you to add a table to Firebase that only contains the usernames, and the .uid's that they belong to. You will need to first read through that table to make sure that no one else has that username, then update the table accordingly:

// This function will check through all of the usernames and return a true or false value in the completion handler
func checkUsernames(_ completion: @escaping(_ success: Bool) -> Void) {
    ref.child("usernames").observeSingleEvent(of: .value, with: { snapshot in
        if let snapshots = snapshot.children.allObjects as? [DataSnapshot] { 
            for snap in snapshots {
                if snap.value == username {
                    completion(false)
                }
            }
            completion(true) 
        } else {
            completion(true) // TODO: check for errors before setting completion
        }     
    })
}

// this function will set the username values in Firebase
func storeUsername() {
    let usernameRef = ref.child("usernames")
    usernameRef.updateChildValues(["\(userDataSource.sharedInstance.id!)" : username])
        }
    }
}

Assuming you have already handled your username variable and set it's value, you will call the functions like this:

checkUsernames({ (success) in
    if success {
        storeUsername()
        // you may also want to update your "users" table here as well
    } else { print("Duplicate Username") } // handle alert or something here
})
Jake
  • 2,126
  • 1
  • 10
  • 23
  • doesn't work, I get error `Type 'DataSnapshot' does not conform to protocol 'Sequence'` – Diana Mar 21 '18 at 14:16
  • Are you trying to store your user's id on login? What is your goal? – Jake Mar 21 '18 at 14:30
  • I'm trying to store user's username, and check unique usernames (is username already exist in different account or not?). For example, if email: anna@gmail.com has username "hellowrold", user margo@gmail.com can't have username "hellowrold" – Diana Mar 21 '18 at 14:33
  • Okay. I've edited my answer, but I need to edit it again to give you a more precise response. One minute. – Jake Mar 21 '18 at 14:34
  • I'm so sorry, I'm a little bit newbie in Firebase and I think I didn't good explain what my problem is. I've login page just with email and password, but in my database I store email and username for each user like this `newUserReference.setValue(["username":String(), "email" : self.emailTextField.text!])`. On next view, user can type username in `usernameField.text` and this value will add in Firebase Database. But if the next user (user 2) will type the same username like previous user, it will block, because username should be unique – Diana Mar 21 '18 at 14:51
  • I tried to make steps from here, but I don't know, why my code doesn't work [link](https://stackoverflow.com/questions/41063953/how-do-i-validate-if-a-username-exists-before-sign-up-in-firebase-and-swift-3) – Diana Mar 21 '18 at 14:51
  • Ohhhh.. not the unique ID that firebase sets for them. – Jake Mar 21 '18 at 14:52
1

You still need to indicate what property you want to order/filter on with queryOrdered(byChild:):

if (usernameField.text?.isEmpty == false){
    ref.child("users").queryOrdered(byChild:"username").queryEqual(toValue: username).observeSingleEvent(of: .value, with: { snapshot in

        if snapshot.exists(){
Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
  • I tried to use this line too, but it doesn't help to block existing usernames in different account. I got this message on console: Your data will be downloaded and filtered on the client. Consider adding ".indexOn": "username" at /users to your security rules for better performance – Diana Mar 21 '18 at 14:27
  • 1
    That warning just means you need to define an index on `/users`. See https://firebase.google.com/docs/database/security/indexing-data or some of these: https://stackoverflow.com/search?tab=votes&q=%5bfirebase%5d%20Consider%20adding%20%22.indexOn%22%20%20to%20your%20security%20rules%20for%20better%20performance – Frank van Puffelen Mar 21 '18 at 15:02