Struggling with basic Swift logic (Working with constants, variables and loops) - swift

I want to use 2 Strings that I get with those two "loops" from firebase and use them in another "loop" to upload them with a bunch of other Information.
My problem is, that I somehow can't get the values of fullname and pfp that I downloaded, into the upload to firebase.
Any ideas on how to solve this issue?
func sendToFire(){
let combined = "\(userID)" + "\(number)"
let docRef = db.collection("posts").document(combined)
let description = self.textPost.text
let nameRef = db.collection("users").document(userID)
var fullname = ""
var pfp = ""
if fireImage == nil {
nameRef.getDocument { (document, error) in
if let document = document{
fullname = document.get("fullname") as! String
}else{
print("Coulnt get fullname")
}
}
nameRef.getDocument { (document, error) in
if let document = document{
pfp = document.get("profileimage") as! String
}else{
print("Couldn't get profileimage")
}
}
docRef.getDocument { (document, error) in
if let document = document, document.exists {
print("Post ID already taken")
} else {
print("Post Document gets created")
self.db.collection("posts").document(combined).setData([
"description": description!,
"likes": self.likes,
"postType": 0,
"profileImage": pfp,
"time": self.date,
"uid": self.userID,
"username": fullname
]) { err in
if let err = err {
print("Error writing document: \(err)")
} else {
print("Post Document successfully written!")
}
}
}
}
}
}

Add document.exists in the if let
nameRef.getDocument { (document, error) in
if let document = document, document.exists{
fullname = document.get("fullname") as! String
}else{
print("Coulnt get fullname")
}
}
nameRef.getDocument { (document, error) in
if let document = document, document.exists{
pfp = document.get("profileimage") as! String
}else{
print("Couldn't get profileimage")
}
}
Check the actual key names in the response fullname and profileimage.

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)
}
}
}

Await function Swift/SwiftUI

I'm new in swift and SwiftUI and i have a big problem, I hope someone can help me. In fact, I have a function were I use a call to firebase Db, but the function end before the response of firebase. So is there any way to do like an await in swift ? I try to find by myself but everything I try doesn't work.
I put a sample of code, it's maybe going to be clearer.
extension SessionStore {
func checkReferralCode(){
let docRef = db.document(user.referredBy)
docRef.getDocument { (document, error) in
if let document = document, document.exists {
let otherUser = self.changeReferralUserInformation(dataDescription: document)
docRef.setData(otherUser)
self.user.moneyBalance = 1
return
} else {
print("No referral Code")
self.firestoreError = "referralCode_unvalid"
self.user.referredBy = ""
return
}
}
}
func doInscriptionInformation() {
if (self.user.referredBy != "") {
self.checkReferralCode()
if (self.firestoreError == "" ) {
/* it's always go in this way but 1 secs after the firestoreError change */
print("START UPLOAD")
self.determineUploadType()
} else {
return
}
}
}
The output it's gonna be :
$> START UPLOAD
$> No referral Code
I found an answer using semaphore, here the link of the tutorial https://medium.com/#roykronenfeld/semaphores-in-swift-e296ea80f860
Here the code
func checkReferralCode(semaphore: DispatchSemaphore){
let docRef = self.db.document(self.user.referredBy)
semaphore.wait()
docRef.getDocument { (document, error) in
if let document = document, document.exists {
let otherUser = self.changeReferralUserInformation(dataDescription: document)
docRef.setData(otherUser)
self.user.moneyBalance = 1
semaphore.signal()
} else {
self.firestoreError = "referralCode_unvalid"
self.user.referredBy = ""
semaphore.signal()
}
}
}
func doInscriptionInformation() {
let semaphore = DispatchSemaphore(value: 1)
DispatchQueue.global(qos: .userInteractive).async {
if (self.user.referredBy != "") {
self.checkReferralCode(semaphore: semaphore)
semaphore.wait()
if (self.firestoreError == "" ) {
self.determineUploadType()
}
else {
print("No good referral code")
}
semaphore.signal()
}
}
}
Hope that can help someone
make docRef a variable of the class instead of a local variable like so:
class WhateverClassNameYouHave: InheritedClass {
let docRef : DocRef (whatever type it is)
func checkCode() {
self.docRef = /* get firebase doc */
/* Call to firebase function */
docRef.getDocument { (document, error) in
/* Do my stuff*/
} else {
/*change variable to error*/
self.firestoreError = "referralCode_unvalid"
}
}
/*But the fonction end before the response of firebase so my self.firestoreError isn't update */
}

Access variable outside of function Swift

How can I get the value from firstName from the inside:
func saveImage(name: String, postURL:URL, completion: #escaping ((_ url: URL?) -> ())){
//Get sspecific document from current user
let docRef = Firestore.firestore().collection("users").whereField("uid", isEqualTo: Auth.auth().currentUser?.uid ?? "")
var firstName = ""
// Get data
docRef.getDocuments { (querySnapshot, err) in
var firstName = ""
if let err = err {
print("ERROR: ")
print(err.localizedDescription)
return
} else if querySnapshot!.documents.count != 1 {
print("More than one documents or none")
} else {
let document = querySnapshot!.documents.first
let dataDescription = document?.data()
firstName = dataDescription?["firstname"] as! String
}
}
// This uploads the data
let dict = ["title": postDescriptionTitle.text!,
"description": postDescription.text!,
"Address": addressField.text!,
"Zipcode": zipcodeField.text!,
"timestamp": [".sv":"timestamp"],
"Author":firstName,
"postUrl": postURL.absoluteString]
as [String: Any]
self.ref.child("post").childByAutoId().setValue(dict)
}
It looks like it's out of scope, how can I store it or access it without storing it in another variable?
As you can see, I'm trying to upload the variable firstName to the database. So in this part:
"Author":firstName,
I should be getting the value so I can give it to Author
Just move the "upload data" part inside the completion block like this:
func saveImage(name: String, postURL:URL, completion: #escaping ((_ url: URL?) -> ())) {
//Get sspecific document from current user
let docRef = Firestore.firestore().collection("users").whereField("uid", isEqualTo: Auth.auth().currentUser?.uid ?? "")
// Get data
docRef.getDocuments { (querySnapshot, err) in
if let err = err {
print("ERROR: ")
print(err.localizedDescription)
return
} else if querySnapshot!.documents.count != 1 {
print("More than one documents or none")
} else {
let document = querySnapshot!.documents.first
let dataDescription = document?.data()
let firstName = dataDescription?["firstname"] as! String
// This uploads the data
let dict = ["title": self.postDescriptionTitle.text!,
"description": self.postDescription.text!,
"Address": self.addressField.text!,
"Zipcode": self.zipcodeField.text!,
"timestamp": [".sv":"timestamp"],
"Author": firstName,
"postUrl": postURL.absoluteString] as [String: Any]
self.ref.child("post").childByAutoId().setValue(dict)
}
}
}
Also for what are you using the completion argument in your saveImage function?

What is the proper way to return a firestore documentID in swift?

I would like to create a function that will return a documentID given a value of a field. I am getting tired of my nested functions. Is there a simple way to have one function that returns the ID ?
Here is what I have been doing. It is an ugly pattern.
public class func getAccountItems(accountName:String) {
let db = Firestore.firestore()
let defaults = UserDefaults.standard
let userId: String! = defaults.string(forKey: "UserUUID")
db.collection("Portfolios")
.whereField("users." + userId, isEqualTo: true)
.limit(to: 1)
.getDocuments() { (querySnapshot, err) in
if let err = err {
print("Error getting documents: \(err)")
} else {
var documentID:String? = nil
for document in querySnapshot!.documents {
print("\(document.documentID) => \(document.data())")
documentID = document.documentID
if(documentID != nil){
do {
let db = Firestore.firestore()
let defaults = UserDefaults.standard
let portfolioId: String! = defaults.string(forKey: listDocKey)
db.collection("Portfolios").document(portfolioId).collection("Accounts").whereField("name", isEqualTo: accountName)
.getDocuments(){ (querySnapshot, err) in
if let err = err {
print("Error getting documents: \(err)")
} else {
if querySnapshot!.documents.count == 1 {
for document in querySnapshot!.documents {
db.collection("Portfolios").document(documentID!).collection("Accounts").document(document.documentID).collection("Items")
.getDocuments() { (querySnapshot, err) in
if let err = err {
print("Error getting documents: \(err)")
} else {
var items:[INDX01FirestoreService.PortfolioItem] = []
for document in querySnapshot!.documents {
print("\(accountName): \(document.documentID) => \(document.data())")
let pi = try! FirestoreDecoder().decode(INDX01FirestoreService.PortfolioItem.self, from: document.data())
items.append(pi )
}
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "AccountItemsReceived"), object: nil, userInfo: ["items": items])
}
}
}
}else{
print ("Error count is \(querySnapshot!.documents.count)")
}
}
}
}
}
}
}
}
}
Since Firestore is an async call I either do it this way or I send a notification. I don't like sending notifications all over the place.
Cant post a comment but one thing why do you have so much db references
let db = Firestore.firestore()
this should give you id of the document like you have
documentID = document.documentID
Post here how your data structure looks like and what ids you want to get also have in mind you should store id in each document.
I try to help you.
I decided to just store the documentID in UserDefaults as that handles most of the use cases. Otherwise I do the above, search, find, then process

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.")
}
}
}