Swift - Fetch elements from Firestore

Viewed 28

I have a problem with this function:

func fetchGameFromDB(completionHandler: @escaping ([GamesObject]) -> Void) {


    db.collection("games").getDocuments { (querySnapshot, err) in
        if let err = err {
            print("Error: \(err)")
        } else {
            self.gameObject = []
            for document in querySnapshot!.documents {
                print("document \(document.data())")
                if let name = document.data()["name"] as? String {
                    let docRef = self.db.collection("games").document(name)
                    docRef.getDocument { document, error in
                        if let document = document {
                            let data = document.data()
                            let name = data?["name"] as? String ?? ""
                            let urlStanding = data?["urlStanding"] as? String ?? ""
                            let img = data?["gameImg"] as? String ?? ""
                            let urlUpcoming = data?["urlUpcoming"] as? String ?? ""
                            self.gameObject.append(GamesObject(name: name, gameImg: img, urlStanding: urlStanding, urlUpcoming: urlUpcoming))
                            // here i have elements in gameObject
                        }
                        // here i have elements in gameObject
                    }
                    // here gameObject = []
                }
                // here gameObject = []
            }
            completionHandler(self.gameObject)
            // here gameObject = []
        }
    }
}

I get my data well and I add it to my array but when I get to the completionHandler the array is empty.

2 Answers

I find solution, i check if gameObject.count == querySnapshot?.count then I use my completionHandler

func fetchGameFromDB(completionHandler: @escaping ([GamesObject]) -> Void) {
    db.collection("games").getDocuments { (querySnapshot, err) in
        if let err = err {
            print("Error: \(err)")
        } else {
            self.gameObject = []
            querySnapshot?.documents.forEach({ (document) in
                if let name = document.data()["name"] as? String {
                    let docRef = self.db.collection("games").document(name)
                    docRef.getDocument { document, error in
                        if let document = document {
                            let data = document.data()
                            let name = data?["name"] as? String ?? ""
                            let urlStanding = data?["urlStanding"] as? String ?? ""
                            let img = data?["gameImg"] as? String ?? ""
                            let urlUpcoming = data?["urlUpcoming"] as? String ?? ""
                            self.gameObject.append(GamesObject(name: name, gameImg: img, urlStanding: urlStanding, urlUpcoming: urlUpcoming))
                            if self.gameObject.count == querySnapshot?.count  {
                                completionHandler(self.gameObject)
                            }
                        }
                    }
                }
            })
        }
}

}

the first answer there is no problem as long as the missing documents do not exist. but, that cannot be escaped if any of the documents are missing.

how about use to 'DispatchGroup' ?

func fetchGameFromDB(completionHandler: @escaping([GamesObject]) -> Void) {

    db.collection("games").getDocuments { (querySnapshot, error) in 
        guard let docs = querySnapshot?.documents, !docs.isEmpty else {
            if let error = error {
                print(error)
            }
            
            return
        }

        let group = DispatchGroup()
        docs.forEach { doc in 
            group.enter()

            guard let name = doc.data()["name"] as? String else {
                group.leave()
                return
            }

            let docRef = self.db.collection("games").document(name)
            docRef.getDocument { document, error in 
                if let document = document, let data = document.data() {

                    //do something...
                    
                    gameObjects.append(GamesObject(...)) //init object
                }
                
                group.leave()       
            }
        }

        group.notify(queue: .main) {
            completionHandler(gameObjects)
        }
    }        
}
Related