0

I am trying to get data back from the Firebase Firestore but have come in to one or maybe more problems

Here is my code

I a trying to get a specific document with the id of the current user id

import SwiftUI
import Firebase
import FirebaseFirestore
import FirebaseFirestoreSwift


class UsersModel: ObservableObject {
    
    @Published var userData = [UserData]()
    
    let userID = Auth.auth().currentUser!.uid
    
    private var db = Firestore.firestore()
    
    func fetchData() {
            
            db.collection("users").document(userID).addSnapshotListener { (querySnapshot, error) in
                guard let document = QuerySnapshot?.documents() else {
                    print("No documents")
                    return
                }
                
                self.userData = document.compactMap{(QueryDocumentSnapshot) -> UserData? in
                    return try? QueryDocumentSnapshot.data(as: UserData.self)
                }
            }
        }
}

but on this line guard let document = QuerySnapshot?.documents() else { I get this error Type 'QuerySnapshot?' has no member 'documents'

I am using the Coddle protocol

Here is my UserData

import SwiftUI
import FirebaseFirestoreSwift

struct UserData: Identifiable, Codable {
    @DocumentID var id: String?
    var username: String
    var ImageURl: URL
}

What am I doing wrong and how can I fix this please

Many Thanks for your help

Tom1753
  • 1
  • 1
  • Try `QuerySnapshot?.documents` instead of `QuerySnapshot?.documents()`, without `()` – Dharmaraj Mar 19 '22 at 09:41
  • I now get this error on the same line 'Type of expression is ambiguous without more context'. – Tom1753 Mar 19 '22 at 09:51
  • [This answer](https://stackoverflow.com/questions/40894582/type-of-expression-is-ambiguous-without-more-context-swift) might be useful for the another issue. – Dharmaraj Mar 19 '22 at 09:53

2 Answers2

1

Your snapshot is already a document so you can't query for 'documents' because it's not a collection

All you need to do is get your query snapshot from the listener closure, [querySnapshot] and get it's data like so:

func fetchData() {    
    db.collection("users").document(userID).addSnapshotListener { (documentSnapshot, error) in
        guard let document = documentSnapshot?.data() else {
            print("No documents")
            return
        }
        
        self.userData = document.compactMap{(QueryDocumentSnapshot) -> UserData? in
            return try? QueryDocumentSnapshot.data(as: UserData.self)
        }
    }
}
Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
Denzel
  • 309
  • 1
  • 8
  • on the return try? line I get this error `Value of tuple type 'Dictionary.Element' (aka '(key: String, value: Any)') has no member 'data'` – Tom1753 Mar 19 '22 at 11:31
0

It appears you are attempting to read in a single user's data, which would be a single document. No reason to addSnapshotListener unless you want to be notified of changes.

Also, there's no reason to .compactMap because the users data can be directly read from the document.

There are many options for reading a single document and mapping it to an object; here's two:

Here's a simplifed object

struct UserData: Identifiable, Codable {
    @DocumentID var id: String?
    var username: String
    var ImageUrl: String
}

Option 1 to read the user using getDocument { (document, error) and then casting the document to a User object after being read

func readUser() {
    let userID = "uid_0"
    let docRef = self.db.collection("users").document(userID)

    docRef.getDocument { (document, error) in
        if let err = error {
            print(err.localizedDescription)
            return
        }

        if let doc = document {
            let user = try! doc.data(as: UserData.self)
            print(user.username, user.ImageUrl)
        }
    }
}

and then the second, super simple (and way cooler) option to map the users data to the user object when it's read in

func readUser2() {
    let userID = "uid_0"
    let docRef = self.db.collection("users").document(userID)

    docRef.getDocument(as: UserData.self, completion: { result in
        switch result {
        case .success(let user):
            print(user.username, user.ImageUrl)
        case .failure(let error):
            print(error.localizedDescription)
        }
    })
}
Jay
  • 34,438
  • 18
  • 52
  • 81