Firebase Datadescription Returns Empty Array

Firebase datadescription returns empty array

The main issue here is that FireStore is asynchronous. It takes time for Firestore to return data from the internet and that data is only valid inside the closure following the getDocument.

That means the print(Groups) function will execute before the code inside the closure, so it's empty. Moving the print inside the closure will work.

var Groups = [String:Any]()
let docRef = AppDelegate.db.collection("JoinedGroups").document(user)
docRef.getDocument(source: .cache) { (document, error) in
if let document = document {
let dataDescription = document.data()
self.Groups = dataDescription! // unwrapping here
print("Cached document data: \(dataDescription)")
} else {
print("Document does not exist in cache")
}
print(self.Groups)
}
}

May I also suggest you stick with naming conventions where vars are lowercases, e.g. groups instead of Groups. Upper case are usually for class definitions UserClass or GroupClass.

One last thing... documentID's (their 'key') cannot be changed. What that means is if your structure is this

JoinedGroups
jimmy@email.com
name: "Jimmy"
fav_food: "Pizza"

and you reference that user throughout your app, when they decide to change their email provider, you'll have to go through everywhere in your strucutre, read in that node, delete the node and write it back out with the updated email. How you fix it is it disassociate the documentID (key) from the data it contains

JoinedGroups
users_uid
name: "Jimmy"
fav_food: "Pizza"

as uid's never change, the email can change 20 times and not affect your app.

Cannot get documents from Firestore in Swift

Thanks to Jay's comment, I managed to fix the problem by having clientEmail as a global variable and using a completion handler to assign the value in this function.

func getClientEmail() {
// Get email of client for corresponding contractor
db.collection("Clients").getDocuments(completion: { (querySnapshot, err) in
if let err = err {
print(err.localizedDescription)
return
} else {
for document in querySnapshot!.documents {
let result = Result {
try document.data(as: User.self)
}

switch result {
case .success(let client):
if let client = client {
if client.placementIDs[0] == self.user?.placementIDs[0] {
self.clientEmail = client.email
}
} else {
print("Document doesn't exist")
}
case .failure(let error):
print("Error decoding user: \(error)")
}
}
}
})
}

SearchBar problem while trying to search Firestore and reload the tableview

The issue in your question is that Firestore is asynchronous.

It takes time for Firestore to return documents you've requested and that data will only be valid within the closure calling the function. The code outside the closure will execute way before the data is available within the closure.

So here's what's going on.

func searchIngredients(text: String) -> Array<Any>{
let db = Firestore.firestore()
db.collection("Ingredients").whereField("compName", arrayContains: text).getDocuments{ (querySnapshot, err) in
//the data has returned from firebase and is valid
}
//the code below here will execute *before* the code in the above closure
self.tableView.reloadData()
ingredientsArray = searchedIngredientsArray
return ingredientsArray
}

what's happening is the tableView is being refreshed before there's any data in the array.

You're also returning the ingredientsArray before it's populated. More importantly, attempting to return a value from an asynchronous function can (and should) generally be avoided.

The fix is to handle the data within the closure

class ViewController: NSViewController {
var ingredientArray = [String]()
func searchIngredients(text: String) {
let db = Firestore.firestore()
db.collection("Ingredients").whereField("compName", arrayContains: text).getDocuments{ (querySnapshot, err) in
//the data has returned from firebase and is valid
//populate the class var array with data from firebase
// self.ingredientArray.append(some string)
//refresh the tableview
}
}

Note that the searchIngredients function should not return a value - nor does it need to

Storing asynchronous Cloud Firestore query results in Swift

You need a dispatch group in addition to a completion

func convertToNames(arr: [String],completion:@escaping(([String]) -> ())) {

var newArr : [String] = []
let g = DispatchGroup()
for id in arr {
let docRef = db.collection("users").document(id)
g.enter()
docRef.getDocument { (document, error) in
if let document = document, document.exists {
let dataDescription = document.data().map(String.init(describing:)) ?? "nil"
let data = document.get("firstname") ?? "nil"

print("gotten data: \(data)")
newArr.append(String(describing: data))
g.leave()
} else {
print("Document does not exist")
g.leave()
}
}
}

g.notify(queue:.main) {
print("NEW ARRAY: \(newArr)")
completion(newArr)
}
}

Call

convertToNames(arr:<#arr#>) { res in
print(res)
}


Related Topics



Leave a reply



Submit