Einzelnes Feld aus Firestore Document lesen

    Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

    Aufgrund der Corona-Krise: Die Veröffentlichung von Stellenangeboten und -gesuchen ist bis 31.3.2023 kostenfrei. Das beinhaltet auch Angebote und Gesuche von und für Freischaffende und Selbstständige.

    • Einzelnes Feld aus Firestore Document lesen

      Hallo,
      bin neu hier und auch recht neu in der Swift Welt.
      Ich arbeite gerade an einer App bei der es um Gäste Verwaltung geht.
      Jeder Gast der angelegt wird, hat eine Referenz zum User der ihn angelegt hat (user ID)

      Ds Gast Model sieht so aus:

      Quellcode

      1. import FirebaseFirestoreSwift
      2. struct Guest: Identifiable, Codable {
      3. @DocumentID var id: String?
      4. let fullname: String
      5. let company: String
      6. let created: Date
      7. let uid: String
      8. }




      das User Model sieht so aus:

      Quellcode

      1. import FirebaseFirestoreSwift
      2. struct User: Identifiable, Decodable {
      3. @DocumentID var id: String?
      4. let fullname: String
      5. let email: String
      6. var isAdmin = false
      7. var isNonTariff = false
      8. var isPresent = false
      9. }

      in einer View möchte ich nun den Gast nebst seinem Contact (der User der Ihn angelegt hat) anzeigen.
      Also hole ich mir alle Gäste aus dem Firestore:

      Quellcode

      1. func getAll(completion: @escaping ([Guest]) -> Void) {
      2. guard let token = UserDefaults.standard.string(forKey: "companyToken") else { return }
      3. db.document(token)
      4. .collection("guests")
      5. .order(by: "created", descending: false)
      6. .getDocuments { snapshot, _ in
      7. guard let documents = snapshot?.documents else { return }
      8. let guests = documents.compactMap({try? $0.data(as: Guest.self)})
      9. completion(guests)
      10. }
      11. }
      Alles anzeigen

      und im ViewModel dann:

      Quellcode

      1. @Published var guests = [GuestViewModel]()
      2. service.getAll { guests in
      3. self.guests = guests.map({ GuestViewModel.init(guest: $0, service: self.service) })
      4. }
      5. struct GuestViewModel: Identifiable {
      6. let guest: Guest
      7. let service: DataServiceProtocol
      8. var id: String { guest.id ?? "" }
      9. var fullname: String { guest.fullname }
      10. var company: String { guest.company }
      11. var contact: String {
      12. service.getUsersName(forId: guest.uid)
      13. }
      14. }
      Alles anzeigen

      und hier noch die getUsersName() Funktion:

      Quellcode

      1. func getUsersName(forId id: String) -> String {
      2. guard let token = UserDefaults.standard.string(forKey: "companyToken") else { return "" }
      3. var name = ""
      4. db.document(token)
      5. .collection("users")
      6. .document(id)
      7. .getDocument { document, error in
      8. guard let document = document, document.exists else { return }
      9. guard let fieldValue = document.get("fullname") as? String else { return }
      10. name = fieldValue
      11. }
      12. return name
      13. }
      Alles anzeigen

      wenn ich im obigen code in Zeile 10 ein print Statement setze und den Inhalt von name abfrage steht genau drin was ich haben möchte.
      aber im return ist name leer.

      was mach ich denn da falsch?

      Danke Euch
      Grüße
      Micha
    • Hmm, also wenn ich die Definition über Option Klick angucke ist da nix mit async.

      ich habs jetzt mal so geändert:

      Quellcode

      1. func getUsersName(forId id: String, completion: @escaping(String) -> Void){
      2. guard let token = UserDefaults.standard.string(forKey: "companyToken") else { return }
      3. db.document(token).collection("users").document(id).getDocument(as: User.self) { result in
      4. switch result {
      5. case .success(let user):
      6. completion(user.fullname)
      7. case .failure:
      8. completion("")
      9. }
      10. }
      11. }
      Alles anzeigen

      und im ViewModel dann:

      Quellcode

      1. class GuestViewModel: Identifiable {
      2. private let guest: Guest
      3. var id: String { guest.id ?? "" }
      4. var fullname: String { guest.fullname }
      5. var company: String { guest.company }
      6. var contact = ""
      7. init(guest: Guest, service: DataServiceProtocol) {
      8. self.guest = guest
      9. service.getUsersName(forId: guest.uid) { name in
      10. self.contact = name
      11. }
      12. }
      13. }
      Alles anzeigen
      wenn ich nen Haltepunkt auf Zeile 12 setze enthält name auch den Namen den ich benötige aber self.contact hat den Namen nicht mehr danach
    • Da gibt es viele Möglichkeiten, wie z.B. die Anzeige aktualisieren, nachdem alle Daten geladen sind.

      Alternativ könntest Du es mal über Async await probieren. Ich habe dies jedoch noch nicht verwendet. Evtl. funktioniert es damit nicht.

      BTW: Wo kommen die Daten für Guest her? Evtl. solltest Du die Daten für Guest und contact gleichzeitig ermitteln, da Guest sicherlich auch asynchron ermittelt wird, oder?

      Ich sehe gerade, dass Du dies sehr gut in der Funktion getAll() erledigen könntest. Die ist ja schon asynchron und könnte zu den Guest Daten dann auch die jeweiligen Kontakte ermitteln. ;)