Check and Add a document to the Firestore database (swift) - swift

first I want to check if a doc with the Uid of the user is already created and if not, it should create a doc with the Uid of the user as a title.
Here is my code: (Somehow it doesnt work)
It gives me the error: Value of type 'CollectionReference' has no member 'doc'
#IBAction func GoogleSignIn(_ sender: Any) {
let db = Firestore.firestore()
guard let uid = Auth.auth().currentUser?.uid else { return }
let docRef = db.collection("users").document(uid)
let user: GIDGoogleUser = GIDSignIn.sharedInstance()!.currentUser
let fullName = user.profile.name
let email = user.profile.email
docRef.getDocument { (document, error) in
if let document = document {
if document.exists{
print("User already in Database")
} else {
print("User needs to get signed into Database")
db.collection("users").doc(uid).set([
"fullname" : fullName,
"email": email
])
}
GIDSignIn.sharedInstance()?.signIn()
}

is ".doc" a method? Don't you want db.collection("users").document(uid)

Related

firestore fetch subcollection

I'm trying to fetch subcollection of my users document with code below
func readData(){
let userId = Auth.auth().currentUser?.uid
self.db.collection("users/\(userId)/saved").getDocuments { (snapshot, err) in
if let err = err {
print("err")
}
if let userId != nil {
for document in snapshot!.documents {
let docId = document.documentID
let cty = document.get("city") as! String
let ccode = document.get("code") as! String
let countr = document.get("country") as! String
print(cty, ccode, countr,docId)
}
}
}
but my code doesn't print anything, I don't understand the problem, documents exsist, see picture below
You're using illegal syntax with the userId check in the snapshot return but the logic flow is the bigger problem. I would recommend you check if the user is signed in before grabbing the subcollection and checking if there is a viable snapshot instead of checking the state of authentication.
func readData() {
guard let userId = Auth.auth().currentUser?.uid else {
return
}
db.collection("users/\(userId)/saved").getDocuments { (snapshot, error) in
guard let snapshot = snapshot else {
if let error = error {
print(error)
}
return
}
for doc in snapshot.documents {
guard let city = doc.get("city") as? String,
let code = doc.get("code") as? String,
let country = doc.get("country") as? String else {
continue // continue document loop
}
let docId = doc.documentID
print(city, code, country, docId)
}
}
}

How to get the first name of the logged in User from firebase using Swiftui?

How to to get the first name of the current user which is logged in.
This is how my try looks like:
var ref: DatabaseReference!
ref = Database.database().reference()
let db = Firestore.firestore()
let userID = Auth.auth().currentUser?.uid
print(userID)
ref.child("users").child(userID!).observeSingleEvent(of: .value, with: { (snapshot) in
// Get user value
let value = snapshot.value as? NSDictionary
let username = value?["firstname"] as? String ?? ""
print(username)
// ...
}) { (error) in
print(error.localizedDescription)
}
Try the following:
let userId = Auth.auth().currentUser?.uid else { return }
let docRef = db.collection("users").document(userId)
docRef.getDocument(source: .cache) { (document, error) in
if let document = document {
let name = document.get("firstname")
print("Cached document data: \(name)")
} else {
print("Document does not exist in cache")
}
}
You are using cloud firestore but in your code, you are using the Realtime database. You need to check the following docs related to cloud firestore:
https://firebase.google.com/docs/firestore/quickstart

swift firestore check if documents exists

using swift and firestore I want to check the "Taken User Names" collection to see if a username has been taken and if it has alert the user it taken otherwise if it's still available I want to create the file.
The gist of what I want to do is outlined below, I can save the data no problem though its the checking to see if its document exists then taking action that I cannot figure out
func nextButtonPressed(){
let db = Firestore.firestore()
if usernameTextField.text != ""{
guard let username = usernameTextField.text else { return }
let docRef = db.collection("Taken User Names").document(username)
// check if username exists{
//if exists alert user "sorry user name taken
} else {
// if user name doesn't exist
db.collection("Taken User Names").document("trinidad")
.setData(["Taken User Name" : (username)]) {
(error: Error?) in
if let error = error {
print("\(error.localizedDescription)")
} else {
print("document was succesfully created and written")
}
}
}
}
In a cleaner way:
let docRef = db.collection("collection").document("doc")
docRef.getDocument { (document, error) in
if document.exists {
print("Document data: \(document.data())")
} else {
print("Document does not exist")
}
}
func nextButtonPressed(){
let db = Firestore.firestore()
nextButton.isEnabled = false
if usernameTextField.text != ""{
guard let username = usernameTextField.text else { return }
guard let uid = Auth.auth().currentUser?.uid else { return }
let docRef = db.collection("Taken User Names").document(username)
docRef.getDocument { (document, error) in
if let document = document {
if document.exists{
print("Document data: \(document.data())")
self.alertTheUser(title: "Username Taken", message: "please choose again")
self.nextButton.isEnabled = true
} else {
print("Document does not exist")
}
}
}
}
}
try the following:
let db = Firestore.firestore()
guard let username = userNameTextField.text else { return }
let docRef = db.collection("users").whereField("username", isEqualTo: username).limit(to: 1)
docRef.getDocuments { (querysnapshot, error) in
if error != nil {
print("Document Error: ", error!)
} else {
if let doc = querysnapshot?.documents, !doc.isEmpty {
print("Document is present.")
}
}
}

Check Firebase Storage before creating a new profile Image URL

I am having a bit of an issue checking Firebase Storage when a user logs into my app. When a user logs in an image is created and stored successfully in Firebase database and storage, but every time a user logs out and logs back into the app the profileImage file (not the child value url string) is duplicated in Firebase Storage as a new and separate image file.
I would like the app when logging in to check the Firebase storage for the profileImage file, and if it exists then do not re-create that same image in storage. I understand the logic of checking Firebase for image and if does not exist, than create new image. I am just having some trouble with the syntax. Thanks for help in advance!
// login user with Facebook
func loginWithFacebook() {
let accessToken = FBSDKAccessToken.current()
guard let accessTokenString = accessToken?.tokenString else { return }
let credentials = FIRFacebookAuthProvider.credential(withAccessToken: accessTokenString)
FIRAuth.auth()?.signIn(with: credentials, completion: { (user, error) in
if error != nil {
print("Something went wrong with our FB user: ", error ?? "")
return
}
guard let uid = user?.uid else {
return
}
let imageName = NSUUID().uuidString
let storageRef = FIRStorage.storage().reference().child("profile_images").child("\(imageName).png")
let photoUrl = user?.photoURL
// check to see if current user already has stored image with URL
if FIRStorage.storage().reference().child("profile_images").child("\(imageName).png") == nil {
if let imageData = NSData(contentsOf: photoUrl!) {
storageRef.put(imageData as Data, metadata:nil) {
(metadata, error) in
if error != nil {
print(error!)
return
} else {
if let profileImageUrl = metadata?.downloadURL()?.absoluteString {
let values = ["name": user!.displayName!, "email": user!.email!, "profileImageUrl": profileImageUrl]
self.registerUserWithUID(uid: uid, values: values as [String : AnyObject])
}
}
}
}
} else {
print("image already exists")
}
print("Successfully logged in with our user: ", user ?? "")
self.delegate?.finishLoggingIn()
})
private func registerUserWithUID(uid: String, values: [String: AnyObject]) {
// create items in database upon creating user ---------------
let ref = FIRDatabase.database().reference()
let usersReference = ref.child("users").child(uid)
usersReference.updateChildValues(values, withCompletionBlock: { (err, ref) in
if err != nil {
print(err!)
return
}
print("user has been saved to Firebase database")
})
}
I think the issue is with the "if" condition. You are referencing the location, but not checking with the actual data in that location.
You can implement that using .observerSingleEventOf().
private func checkUser (imageName:String, _ completionHandler: #escaping(Bool) -> Void)
{
let userExists = FIRStorage.storage().reference().child("profile_images")
userExists.observeSingleEvent(of: .value, with:{(snapshot) in
if snapshot.hasChild(imageName){
print ("Image already exists")
completionHandler(false)
}
else
{
print ("Image does not exist")
print ("store the image")
}
})
}
`

How do update a value inside my Firebase Database from a different class?

I have a Registration Class that has 3 textfields for a username, email and password. When the user hits the Sign Up button, a handleRegister() function is called. This function takes the three values from these textfields.text and sends them to my Firebase database under a child node, containing their user id like in the image below:
My problem is that I want to be able to UPDATE any 3 of these values (email, name, password) OUTSIDE of the registration class. How do I do achieve this? Thank you. Here registration my code:
func handleRegister() {
guard let email = emailTextField.text, let password = passwordTextField.text, let name = usernameTextField.text else {
return
}
FIRAuth.auth()?.createUser(withEmail: email, password: password, completion: { (user: FIRUser?, error) in
if error != nil {
return
}
guard let uid = user?.uid else {
return
}
//successfully registered user.
let imageName = NSUUID().uuidString
let storageRef = FIRStorage.storage().reference().child("profile_images").child("\(imageName).png")
if let uploadData = UIImagePNGRepresentation(self.profileImageView.image!) {
storageRef.put(uploadData, metadata: nil, completion: { (metadata, error) in
if error != nil {
return
}
if let profileImageUrl = metadata?.downloadURL()?.absoluteString {
let values = ["name": name, "email": email, "password": password, "profileImageUrl": profileImageUrl]
self.registerUserIntoDatabaseWithUID(uid: uid, values: values as [String : AnyObject])
}
})
}
})
}
private func registerUserIntoDatabaseWithUID(uid: String, values: [String: AnyObject]) {
let ref = FIRDatabase.database().reference()
let usersReference = ref.child("users").child(uid)
usersReference.updateChildValues(values, withCompletionBlock: { (err, ref) in
if err != nil {
return
}
print("Successfully saved user to database.")
self.dismiss(animated: true, completion: nil)
})
}
You have two options:
Option 1: You need to save your user's database ID somewhere so you can use it later on in the app for situations just like this. You can save the ID in your Userdefaults or somewhere else that's a bit more secure.
Option 2: You can retrieve the ID of the logged in user by using Auth.auth()?.currentUser?.uid
guard let uid = Auth.auth()?.currentUser?.uid else { return }
When you have this ID you can update the value in the database like you are doing in registerUserIntoDatabaseWithUID().
func updateEmailAddress(text: String) {
guard let uid = Auth.auth()?.currentUser?.uid else { return }
let userReference = Database.database().reference.child("users/(uid)")
let values = ["email": text]
// Update the "email" value in the database for the logged in user
userReference.updateChildValues(values, withCompletionBlock: { (error, ref) in
if error != nil {
print(error.localizedDescription)
return
}
print("Successfully saved user to database.")
self.dismiss(animated: true, completion: nil)
})
}
Nota Bene
If you have any questions regarding this answer please add a comment.
The difference between this and the other answer is that I am
indicating how you can update in multiple locations as requested.
You'd want to look at using the data fan out approach. It deals with writing the data at mulitple locations. Here is a quick code sample:
let key = ref.child("posts").childByAutoId().key
let post = ["uid": userID,
"author": username,
"title": title,
"body": body]
let childUpdates = ["/posts/\(key)": post,
"/user-posts/\(userID)/\(key)/": post]
ref.updateChildValues(childUpdates)
To read more about this approach see the documentation at:
https://firebase.google.com/docs/database/ios/read-and-write#update_specific_fields