I'm trying to map a "user" retrieved from my Firestore database to a user struct I've defined in my code but I don't think I properly understand the mapping features in swift.
How do I go about mapping the user retrieved into the struct?
Struct
struct User {
// Properties
var firstName: String
var lastName: String
var userName: String
var email: String
init(firstName: String, lastName: String, userName: String, email: String) {
self.firstName = firstName
self.lastName = lastName
self.userName = userName
self.email = email
}
}
Function that gets user from Firestore
func getUser(UID: String) {
// Firebase setup
settings.areTimestampsInSnapshotsEnabled = true
db.settings = settings
db.collection("users").document(UID).getDocument { (document, error) in
if let error = error {
print("Error: \(error.localizedDescription)")
} else {
print(document!.data()!)
}
}
}
A queried Firestore document is of type [String: Any]
, so configure your initializer to accept that kind of dictionary. Because you're working with a database return, there is never a guarantee that the data will be fully intact, so I would suggest making your initializer failable, which just means that it can return nil
(it can fail).
I took your example and made the email
property optional. In the example below, only three of the four properties are necessary to instantiate the User
object.
let info: [String: Any] = ["hasFriends": true]
let firestoreData: [String: Any] = ["firstName": "lance", "lastName": "stevenson", "userName": "lstevenson", "info": info]
struct User {
var firstName: String
var lastName: String
var userName: String
var info: [String: Any]
var email: String?
var hasFriends: Bool
init?(data: [String: Any]) {
guard let firstName = data["firstName"] as? String,
let lastName = data["lastName"] as? String,
let userName = data["userName"] as? String,
let info = data["info"] as? [String: Any],
let hasFriends = info["hasFriends"] as? Bool else {
return nil
}
self.firstName = firstName
self.lastName = lastName
self.userName = userName
self.info = info
self.hasFriends = hasFriends
self.email = data["email"] as? String // User will be created even if this is nil
}
}
if let user = User(data: firestoreData) {
print(user.hasFriends) // true
}
I would not suggest that you use Swift's mapping tool for this because you will likely be dealing with varying types of values within the same dictionary for different models. And the code to map this dictionary with those variables in an initializer would not be pretty.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With