user5812721 user5812721 - 5 months ago 36
iOS Question

Finding an uid by email in Firebase

I first attempted to instantiate each user in the Database as so:

emails : {
email: "jerry@gmail.com" {
uid: "x"
}
}


I quickly found out that I can't store an email because it has an
@
and
.
. I was originally going to do an user look up as so:

func userLookUpByEmail (email: String) -> String {
var userID: String = "nil"

ref.queryOrderedByChild("emails").queryEqualToValue(email).observeSingleEventOfType(.ChildAdded, withBlock: { snapshot in
if snapshot.value != nil {
print(snapshot.value)
userID = snapshot.value as! String
}
else {
print ("user not found")
userID = "nil"
}
})
return userID
}


However, I'm realizing that won't work. What is an effective way to receive an uid from providing an email?

Answer

First of all, you are correct that you cannot store certain characters in the database. According to the Firebase docs, (https://firebase.google.com/docs/database/ios/structure-data)

If you create your own keys, they must be UTF-8 encoded, can be a maximum of 768 bytes, and cannot contain ., $, #, [, ], /, or ASCII control characters 0-31 or 127.

As you can see, however, the "@" symbol is not one of them. As for the dot, you can have a function that replaces the dot with another character. For example, "•". Here is an example:

func createNewEmail(oldEmail: String) -> String{
    return oldEmail.componentsSeparatedByString(".").joinWithSeparator("•")
}

What that does is it splits the email into an array of "email@example" and "com". Then, it re-joins them with the new character, creating "email@example•com"

If you ever needed the old email, you could just do the same thing in reverse.

func getOldEmail(newEmail: String) -> String{
    return newEmail.componentsSeparatedByString("•").joinWithSeparator(".")
}

You could then format your tree like this

emails:
    email@example•com: UID123456789

Finally, for your original question, the function could be written like this

func userLookUpByEmail (email: String) -> String {
    let newEmail = createNewEmail(email)
    var userID: String = "nil"

    ref.child("emails").child(newEmail).observeSingleEventOfType(.ChildAdded, withBlock: { snapshot in
            if snapshot.value != nil {
                print(snapshot.value)
                userID = snapshot.value as! String
            }
            else {
                print ("user not found")
                userID = "nil"
            }
    })
    return userID
}

However, it is possible that you will get "nil" every time. This is because observeSingleEventOfType is a closure. This means that it runs in the background of your app. Because of this, userID might be returned before it gets changed inside the closure. Instead of returning userID, you might want to run any code based on userID inside of the closure. For example, instead of doing this:

func userLookUpByEmail (email: String) -> String {
    let newEmail = createNewEmail(email)
    var userID: String = "nil"

    ref.child("emails").child(newEmail).observeSingleEventOfType(.ChildAdded, withBlock: { snapshot in
            if snapshot.value != nil {
                print(snapshot.value)
                userID = snapshot.value as! String
            }
            else {
                print ("user not found")
                userID = "nil"
            }
    })
    return userID
}

doSomethingWith(lookUserUpByEmail(email@example.com))

You could do this:

func userLookUpByEmail (email: String){
    let newEmail = createNewEmail(email)
    var userID: String = "nil"

    ref.child("emails").child(newEmail).observeSingleEventOfType(.ChildAdded, withBlock: { snapshot in
            if snapshot.value != nil {
                print(snapshot.value)
                userID = snapshot.value as! String
                doSomethingWith(userID)
            }
            else {
                print ("user not found")
                userID = "nil"
                doSomethingWith(userID)
            }
    })
}
Comments