Reputation: 731
hello, i need some help with function and or possibly closures in that function. I want my function to check the firestore users collection for duplicate documents (usernames). If a duplicate is found i want to display a message, if a duplicate is not found, create a new user. i have folowing code:
func checkIfUserExists(username: String, completion: @escaping (Bool) -> Void) {
let docRef = db.collection("users").document(username)
docRef.getDocument { (document, error) in
if error != nil {
print(error)
} else {
if let document = document {
if document.exists {
completion(true)
} else {
completion(false)
}
}
}
}
}
and i call the function with:
if let username = textField.text, username.count > 8 { // Username needs to be more then 8 Char
checkIfUserExists(username: username) { (doesExist) in
if doesExist {
print("user exists")
} else {
print("new User can be created")
}
}
} else {
print("Username needs to be more then 8 char")
}
}
It works, but i have the feeling it is not good practice and i'm making detours. Is this the right way to do it ?
Upvotes: 1
Views: 371
Reputation: 7546
I think the way you're doing it now should work well, but another option to prevent you from having to do a read of the database before writing is to use security rules. For example, if this is the structure of your users
collection...
users: [
username1: { // doc ID is the username
userid: abcFirebaseUserId, // a field for the uid of the owner of the username
//...etc
}
]
...then you can use the following rules:
match /users/{username} {
allow create: if request.auth.uid != null;
allow update, delete: if resource.data.userId = request.auth.uid;
}
This allows any authenticated user to create a new username, but only the owner of that username can update it or delete it. If you aren't allowing users to change their username, you wouldn't even have to worry about the second rule. Then, in the client, you go right to creating a username, like so:
func createUsername(username: String, completion: @escaping (String?) -> Void) {
guard let userId = Auth.auth().currentUser.uid else {
completion("no current user")
return
}
let docRef = db.collection("users").document(username)
docRef.setData(data:[userId: userId]) { error in
if let error = error {
completion(error.debugDescription)
} else {
completion(nil)
}
}
}
This would write the new username to the database and pass an error to the closure if there is one. If the username already exists, an insufficient permissions
error would be present. When checking if the user exists, you could display the error or alert the user however you wanted.
createUsername(username: username) { err in
if let err = err {
print("user exists")
} else {
print("new User has been created")
}
}
Just a suggestion though. I think they way you're doing it now is fine, too!
Upvotes: 1