Ako spustiť Firestore dotaz vnútri mapu funkciu v Swift

0

Otázka

Som nový SwiftUI a Firebase a snažím sa vybudovať moja prvá aplikácia. Ja som ukladanie Hry dokumenty v Firestore a jednou z oblastí je pole obsahujúce id používateľov hráčov, ako môžete vidieť na obrázku.

Hra štruktúry údajov

Ako už bolo povedané, snažím sa zoznam všetky hry daného používateľa a mať všetkých hráčov uvedených v každej jednej bunky (poradie je dôležité).

S cieľom vytvoriť zoznam hier v UI vytvoril som GameCellListView a GameCellViewModel. Na GameCellViewModel by zaťaženia oboch hier a množstvo užívateľov, ktoré zodpovedajú hráčov každej hre. Avšak nie som schopný načítať používateľov na pole. Musím ísť cez hráčov pole a dotaz na databázu pre každý Identifikátor a pridať Používateľské pole; potom by som mal byť schopný vrátiť sa toto Užívateľské pole. Pretože som používať pre slučky, nemôžem priradenie hodnoty do poľa a potom ju vrátiť. Snažil som sa pomocou mapy(), ale nemôžem vykonať dotaz vnútri neho. Cieľom je nahrať, že "všetky" var s struct, že dostane hre a jeho hráčov GamePlayers(players: [User], game: Game)

Malo by to vyzerať asi útržok kódu nižšie, ale používateľov pole vždy dodávaný prázdny. Táto funkcia sa spúšťa na GameCellViewModel init. Dúfam, že budete môcť pochopiť môj problém a ďakujem vopred! Boli prilepené na to 2 týždne

func loadData() {
        let userId = Auth.auth().currentUser?.uid
        
        db.collection("games")
            .order(by: "createdTime")
            .whereField("userId", isEqualTo: userId)
            .addSnapshotListener { (querySnapshot, error) in
            if let querySnapshot = querySnapshot {
                self.games = querySnapshot.documents.compactMap { document in
                    do {
                        let extractedGame = try document.data(as: Game.self)
                        var user = [User]()
                        let users = extractedGame!.players.map { playerId -> [User] in

                            self.db.collection("users")
                                .whereField("uid", isEqualTo: playerId)
                            .addSnapshotListener { (querySnapshot, error) in
                                guard let documents = querySnapshot?.documents else {
                                    print("No documents")
                                    return
                                }
                                user = documents.compactMap { queryDocumentSnapshot -> User? in
                                    return try? queryDocumentSnapshot.data(as: User.self)
                                    
                                }
                            }
                            return user
                        }
                        
                        self.all.append(GamePlayers(players: users.first ?? [User](), game: extractedGame!))

                        
                        return extractedGame
                    }
                    catch {
                        print(error)
                    }
                    return nil
                }
            }
        }
    }
1

Najlepšiu odpoveď

0

Existuje veľa pohyblivých dielov, váš kód a tak izolovať body zlyhania, by si videl doplnkový kód, takže stačí mať na pamäti, že vopred. Povedal, že, ak ste relatívne nový Firestore alebo Swift potom by som dôrazne odporúčame, aby ste najprv získať handle na túto funkciu, pomocou základná syntax. Akonáhle ste spokojní s vstupy a výstupy z async looping potom by som navrhnúť refactoring kód, pomocou pokročilých syntax, ako ste tu.

Vaše funkcia vyžaduje vykonanie async práce v rámci každej slučky iterácia (každý doklad). Skutočne potrebujete na to dvakrát, async práce v rámci slučky do slučky. Byť istí, že je to to, čo naozaj chcete robiť predtým, než budete pokračovať, pretože tam môže byť čistejšie spôsobmi, ktoré môžu obsahovať efektívnejšie NoSQL údaje architektúry. Bez ohľadu na to, pre účely tejto funkcie, začať s najviac základná syntax je na prácu, ktorá je vyslanie Skupiny v zhode s pre-slučky. Nehanbite sa a hniezdo týchto kým ste si to prácu a potom zvážiť refactoring.

func loadData() {
    // Always safely unwrap the user ID and never assume it is there.
    guard let userId = Auth.auth().currentUser?.uid else {
        return
    }
    // Query the database.
    db.collection("games").whereField("userId", isEqualTo: userId).order(by: "createdTime").addSnapshotListener { (querySnapshot, error) in
        if let querySnapshot = querySnapshot {
            // We need to loop through a number of documents and perform
            // async tasks within them so instantiate a Dispatch Group
            // outside of the loop.
            let dispatch = DispatchGroup()
            
            for doc in querySnapshot.documents {
                // Everytime you enter the loop, enter the dispatch.
                dispatch.enter()
                
                do {
                    // Do something with this document.
                    // You want to perform an additional async task in here,
                    // so fire up another dispatch and repeat these steps.
                    // Consider partitioning these tasks into separate functions
                    // for readability.

                    // At some point in this do block, we must leave the dispatch.
                    dispatch.leave()
                } catch {
                    print(error)
                    
                    // Everytime you leave this iteration, no matter the reason,
                    // even on error, you must leave the dispatch.
                    dispatch.leave()
                    
                    // If there is an error in this iteration, do not return.
                    // Return will return out of the method itself (loadData).
                    // Instead, continue, which will continue the loop.
                    continue
                }
            }
            
            dispatch.notify(queue: .main) {
                // This is the completion handler of the dispatch.
                // Your first round of data is ready, now proceed.
            }
        } else if let error = error {
            // Always log errors to console!!!
            // This should be automatic by now without even having to think about it.
            print(error)
        }
    }
}

Tiež som si všimol, že v druhom súbore asynchrónnej úlohy v rámci druhej slučky, pridávate snímku poslucháčov. Ste si naozaj istý, že chcete urobiť? Nechcem stačí obyčajný dokument získate?

2021-11-23 16:44:21

Vďaka za vašu pomoc! Budem realizovať, a to v priebehu niekoľkých hodín a zistiť, či to funguje na moje. Použil som dispečingu skupín raz, a to zmrazila aplikáciu, ale to bol trochu odlišný od vášho návrhu. Mohli by ste poskytnúť "správny" spôsob, ako to docieliť? Aj keď to vyžaduje zmena štruktúry údajov. Môžem zahrnúť viac kódu, aby ste mohli mať lepšie porozumenie. Ešte raz vďaka!
Álvaro Miguel Samagaio

V iných jazykoch

Táto stránka je v iných jazykoch

Русский
..................................................................................................................
Italiano
..................................................................................................................
Polski
..................................................................................................................
Română
..................................................................................................................
한국어
..................................................................................................................
हिन्दी
..................................................................................................................
Français
..................................................................................................................
Türk
..................................................................................................................
Česk
..................................................................................................................
Português
..................................................................................................................
ไทย
..................................................................................................................
中文
..................................................................................................................
Español
..................................................................................................................