How to use FirebaseFirestoreSwift for read Custom objects

Viewed 35

I'm following the documentation but still getting error expected argument type 'FirestoreSource'. My Xcode target is 15.0. and Firebase version 8.15.0 (SPM)

import FirebaseFirestore
import FirebaseFirestoreSwift

    let db = Firestore.firestore()
    
     func getUser() -> User {
            let docRef = db.collection("users").document(Auth.auth().currentUser)
            docRef.getDocument(as: User.self) { result in      //error: expected argument type 'FirestoreSource'
                switch result {
                case .success(let user):
                    print(user)
                case .failure(let error):
                    print("Error decoding: \(error)")
                }
            }
        }

Here is the custom object User.

struct User: Codable, Identifiable, Hashable {
    @DocumentID var id: String?
    var username: String = ""
    var email: String = ""
    var family: [Family]

    enum CodingKeys: String, CodingKey {
        case id
        case username
        case email
        case family
    }
    
    struct Family: Codable, Hashable {
        var username: String = ""
        var phoneNumber: String = ""
        var email: String = ""

        enum CodingKeys: String, CodingKey {
            case username
            case phoneNumber
            case email
        }
    }
}
1 Answers

There are a few issues with the code

1 - The code attempts to use Auth without importing the FirebaseAuth. Please add

import FirebaseAuth

to the top with the rest of the imports

2 - This call

Auth.auth().currentUser

returns a firebase user object so it won't work here

let docRef = db.collection("users").document(Auth.auth().currentUser)

you probably want to get the users uid

let uid = Auth.auth().currentUser.uid
let docRef = db.collection("users").document(uid)

3 - The function is set up to return a user

func getUser() -> User {

Firebase calls are asynchronous so a user (or anything else) cannot be returned in that fashion. A couple of options are to use a completion handler with an @escaping clause or the newer async await calls which would look like this to retrieve a specific document from a users collection and return the value of the 'name' field

func getUserAsync() async -> String{
    let usersCollection = self.db.collection("users")
    let thisUserDoc = usersCollection.document("uid_0")
    let snapshot = try! await thisUserDoc.getDocument()
    
    let name = snapshot.get("name") as? String ?? "No Name"
    
    return name
}

There are many references to both of those here on SO.

Related