Reputation: 463
I am working on the user profile page of my app, where the user can make changes to the user info, like change their username, name... Each user has their own unique username, I have done that with the following code:
// Function to check if the username is taken
static func checkUsernameUnique(newUserName: String, completion: @escaping(Bool) -> Void) {
let ref = Database.database().reference()
ref.child("Users").queryOrdered(byChild: "Username").queryEqual(toValue: newUserName).observeSingleEvent(of: .value, with: {(snapshot: DataSnapshot) in
if snapshot.exists() {
completion(true)
} else {
completion(false)
}
})
}
This checks if there is a user with the same username. Calling this function:
checkUsernameUnique(newUserName: username) { isExist in
if isExist {
print("Username is taken")
} else {
print("Username is not taken")
}
}
The problem with this is that this checks if there is a user using the same username with all the other users in the database, including the current user. How do I exclude the current user?
Code that I tried with the help of one of the answers
static func checkUsernameUnique(newUserName: String, completion: @escaping(Bool) -> Void) {
let ref = Database.database().reference()
if let userID = Auth.auth().currentUser?.uid {
print(userID)
ref.child("Users").queryOrdered(byChild: "Username").queryEqual(toValue: newUserName).observeSingleEvent(of: .value, with: {(snapshot: DataSnapshot) in
if !snapshot.exists() {
completion(false)
} else {
//Here we will check the given user's UID
snapshot.ref.child("UserID").observeSingleEvent(of: .value, with: { (uidSnapshot) in
//This forced cast should never fail
let uid = uidSnapshot.value as! String
print(uid)
//Now we use FirebaseAuth to cross reference the current user's UID with whatever the "Username" node's sibling node "UserID" is
if Auth.auth().currentUser!.uid == uid {
//The returned user is the same as the current user
completion(false)
} else {
//The returned user is not the same as the current user
completion(true)
}
})
}
})
} else {
ref.child("Users").queryOrdered(byChild: "Username").queryEqual(toValue: newUserName).observeSingleEvent(of: .value, with: {(snapshot: DataSnapshot) in
if snapshot.exists() {
completion(true)
} else {
completion(false)
}
})
}
}
Upvotes: 0
Views: 403
Reputation: 3064
Try this. All we have to do is get the userID of whatever is returned from the query, and check if it equals the current user's uid.
// Function to check if the username is taken
static func checkUsernameUnique(newUserName: String, completion: @escaping(Bool) -> Void) {
let ref = Database.database().reference()
ref.child("Users").queryOrdered(byChild: "Username").queryEqual(toValue: newUserName).observeSingleEvent(of: .value, with: {(snapshot: DataSnapshot) in
guard let json = snapshot.value as? [String:[String:Any]] else {
completion(false)
return
}
//Assuming there will never be more than one database entry with this username, this first element (result) can be unwrapped explicitly without crashing
let result = json.first!.value
let userID = result["UserID"] as! String
if Auth.auth().currentUser!.uid == uid {
completion(false)
} else {
completion(true)
}
})
}
Upvotes: 1
Reputation: 317750
There is no way to conditionally exclude data from a query. You will have to check in your client code if specific data is present in the result, and exclude it from there. Just checking snapshot.exists will not be sufficient in your case - instead, look inside the snapshot to see if it contains the UID of the current user.
Upvotes: 1