8

I have a app that after the user use Firebase auth it store the data on the Firebase database. Before storing the data, I want to check if the username the user give already exist in the database. So if it not exist I could give the user this unique username(like every user have a unique username). So I have a textField where the user enter his username, and then press Next. Then the app should check if the username exist or not, and tell the user if he need to change it.

So the code I used to check if the username exist:

        let databaseRef = FIRDatabase.database().reference()

        databaseRef.child("Users").observeSingleEventOfType(.Value, withBlock: { (snapshot) in

            if snapshot.hasChild(self.usernameTextField.text!){

                print("user exist")

            }else{

                print("user doesn't exist")
            }
        })  

So every time the next button is pressed, this code is called. The problem with this is that the result always remain the same as the first search (even after the textField value change). For example, if I search Jose, and Jose exist in my database so is going to print "user exist". But when I change the textField to name that don't exist, it still show "user exist".

Idan Aviv
  • 1,253
  • 2
  • 13
  • 23
  • Good to hear that you found the mistake. Also have a look at this question for some more considerations when allowing users to claim a unique username: http://stackoverflow.com/questions/25294478/how-do-you-prevent-duplicate-user-properties-in-firebase – Frank van Puffelen Jun 15 '16 at 03:41

2 Answers2

5

I figured out I need to change the .Value to FIRDataEventType.Value

 if (usernameTextField.text?.isEmpty == false){
        let databaseRef = FIRDatabase.database().reference()

         databaseRef.child("Users").observeSingleEventOfType(FIRDataEventType.Value, withBlock: { (snapshot) in

            if snapshot.hasChild(self.usernameTextField.text!){

                print("true rooms exist")

            }else{

                print("false room doesn't exist")
            }


        })
Idan Aviv
  • 1,253
  • 2
  • 13
  • 23
  • 3
    Wouldn't this take longer the more users you have in your database? – WYS May 10 '17 at 10:40
  • Yes you are right. Maybe the smarter way to do it is to have an 'equal' query on the observer. @WYS – Idan Aviv Jun 11 '17 at 10:54
  • 1
    To load only the minimal data needed: `databaseRef.child("Users").child(self.usernameTextField.text!).observeSingleEventOfType(FIRDataEventType.Value, withBlock: { (snapshot) in if snapshot.exists {` – Frank van Puffelen Nov 11 '18 at 15:24
3
struct ModelUser {
    var id: String
    var name: String

    init(data: DataSnapshot) {
        // do init stuff
    }
}

func isUserRegistered(with id: String, completion: @escaping (_ exists: Bool, _ user: ModelUser?) -> ()) {
    DatabaseReference.users.child(id).observeSingleEvent(of: .value) { (snapshot) in
        if snapshot.exists() {
            // user is already in our database
            completion(true, ModelUser(data: snapshot))
        } else {
            // not in database
            completion(false, nil)
        }
    }
}

This worked for me in a similar situation as yours. You can also go the Rx way like this.

enum CustomError: Error {
    case userNotRegistered

    var localizedDescription: String {
        switch self {
        case .userNotRegistered:
            return "Dude is not registered..."
        }
    }
}

func isUserRegistered(with id: String) -> Observable<(ModelUser)> {
    let reference = DatabaseReference.users.child(id)

    return Observable<ModelUser>.create({ observer -> Disposable in
        let listener = reference.observe(.value, with: { snapshot in
            if snapshot.exists() {
                observer.onNext(ModelUser(data: snapshot))
                observer.onCompleted()
            } else {
                observer.onError(CustomError.userNotRegistered)
            }
        })
        return Disposables.create {
            reference.removeObserver(withHandle: listener)
        }
    })
}

The key in both cases is using the .exists() method of the snapshot.