7

I searched for this question, but none of them had an answer that worked for me.

I want to make it so when a user registers an account, it checks to see if the username they have entered already exists, before creating the account. I have tried using querying in firebase, but I just can't seem to get it to work.

Here is an image of what my firebase data looks like: My firebase data tree

How would I use query to find the string for the key "username"?

KENdi
  • 7,576
  • 2
  • 16
  • 31
Big Johnson
  • 207
  • 1
  • 2
  • 11

3 Answers3

9

You can go like this, make one function with completion block to check username is already exist in your Firebase DB and create new user on the basis of it

func checkUserNameAlreadyExist(newUserName: String, completion: @escaping(Bool) -> Void) {

    let ref = FIRDatabase.database().reference()
    ref.child("users").queryOrdered(byChild: "username").queryEqual(toValue: newUserName)
              .observeSingleEvent(of: .value, with: {(snapshot: FIRDataSnapshot) in

        if snapshot.exists() {
            completion(true)
        }
        else {
            completion(false)
        }
    })
}

Now simply call this function when you create new user:

self.checkUserNameAlreadyExist(newUserName: "Johnson") { isExist in
    if isExist {
        print("Username exist")
    }
    else {
        print("create new user")
    }
}
Nirav D
  • 71,513
  • 12
  • 161
  • 183
  • 1
    just wondering did you have to change your permessions to make this work becasue if a user is not authenticated in most situations you wouldn't be able to read from the database at all – Ron Baker Jan 10 '18 at 22:23
3

This is how I do it:

var text = "Your username"

let dbRef = FIRDatabase.database().reference().child("users")
dbRef.queryOrdered(byChild: "name").queryEqual(toValue: text).observeSingleEvent(of: .value, with: { snapshot in
    if !snapshot.exists() {
         // Name doesn't exist
    }

    if let data = snapshot.value as? [String: [String: String]] {
         // it should exist if it reaches here
    }
})

Make sure in your database rules to index the "users" node on "name" for performance optimization.

MarksCode
  • 8,074
  • 15
  • 64
  • 133
0

I do this next way:

The function of register:

@IBAction func signUpButtonTapped(_ sender: Any) {
  User.getItemByLogin(for: userLogin.text!,
                      completion: { userItem in
                       if userItem == nil {
                          self.createAndLogin()
                       } else {
                          self.showAlertThatLoginAlreadyExists()
                       }
  })
}


private func createAndLogin() {
  FIRAuth.auth()!.createUser(withEmail: userEmail.text!,
                             password: userPassword.text!) { user, error in
                                if error == nil {
                                   // log in
                                   FIRAuth.auth()!.signIn(withEmail: self.userEmail.text!,
                                                          password: self.userPassword.text!,
                                                          completion: { result in
                                                           // create new user in database, not in FIRAuth
                                                           User.create(with: self.userLogin.text!)

                                                           self.performSegue(withIdentifier: "fromRegistrationToTabBar", sender: self)
                                   })
                                } else {
                                   print("\(String(describing: error?.localizedDescription))")
                                }
}

private func showAlertThatLoginAlreadyExists() {
  let alert = UIAlertController(title: "Registration failed!",
                                message: "Login already exists.",
                                preferredStyle: .alert)

  alert.addAction(UIAlertAction(title: "Ok", style: .default, handler: nil))

  present(alert, animated: true, completion: nil)
}

My User class function. It's API like class:

static func getItemByLogin(for userLogin: String,
                          completion: @escaping (_ userItem: UserItem?) -> Void) {
  refToUsersNode.observeSingleEvent(of: .value, with: { snapshot in

     for user in snapshot.children {
        let snapshotValue = (user as! FIRDataSnapshot).value as! [String: AnyObject]
        let login = snapshotValue["login"] as! String // getting login of user

        if login == userLogin {
           let userItem = UserItem(snapshot: user as! FIRDataSnapshot)
           completion(userItem)
           return
        }
     }

     completion(nil) // haven't founded user
  })
}

In your way you should swap login with username.

Hope it helps

Vlad Pulichev
  • 3,162
  • 2
  • 20
  • 34