Почему я могу загрузить пользовательский объект в виде поля в документ firestore?

#swift #google-cloud-firestore

# #быстрый #google-cloud-firestore

Вопрос:

Путаница в типах данных Firestore:

Я пытаюсь загрузить пользовательский документ, но исключая тривиальные поля, в качестве поля другого документа Firestore. Что-то вроде «мини-документа пользователя», содержащего только его uid, имя пользователя, имя и фотографию профиля.

Почему в документации Firestore для «Добавления данных» указано, что пользовательские объекты поддерживаются, но в разделе «Поддерживаемые типы данных» объекты не перечислены?

Проблема под рукой:

В нем говорится, что пользовательские объекты преобразуются в поддерживаемые типы данных, однако, когда я следую документации, я получаю сообщение об ошибке при загрузке моего объекта:

Terminating app due to uncaught exception 'FIRInvalidArgumentException', reason: 'Unsupported type: __SwiftValue (found in field tempUserA)'

 public class ConsolidationDataService {
    
    static let instance = ConsolidationDataService()
    let db = Firestore.firestore()
    
    func createNewBucket(bucket: Bucket, user: UserDictionary, collections: [String], handler: @escaping(_ completed: Bool)-> ()){
        let tempUserA = TempUser(
            uid: user.uid,
            username: user.username,
            profileImageURL: user.profileImageURL,
            fullname: user.fullname
        )
        let tempUserB = TempUser(
             uid: "",
             username: "",
             profileImageURL: "",
             fullname: ""
        )
        
        let bucketRef = db.collection("ConsolidatedBuckets").document()
        let consolidatedId = bucketRef.documentID
        let consolidatedBucket = [
            "consolidatedBucketId": consolidatedId,
            "bucketTitle": bucket.bucketTitle,
            "creatorUsername": user.username,
            "creatorUid": user.uid,
            "bucketLogCount": 1,
            "completedCount": 0,
            "uncompletedCount": 1,
            "bucketIds": [bucket.bucketId],
            "bucketImages": [],
            "collectionIds": [],
            "tempUserA": tempUserA,
            "tempUserB": tempUserB
        ] as [String : Any]
        bucketRef.setData(consolidatedBucket){ (error) in
            if error != nil {
                print("There was an error creating a new document in the ConsolidatedCollection")
                handler(false)
            } else {
                print("Uploaded new bucket in the consolidated bucekts colleciton. Named: (bucket.bucketTitle)")
                handler(true)
        }
    }
}

public struct TempUser: Codable {
    let uid: String?
    let username: String?
    let profileImageURL: String?
    let fullname: String?
    
    enum CodingKeys: String, CodingKey {
        case uid
        case username
        case profileImageURL
        case fullname
    }
}
 

Я также попытался загрузить объект со словарем в определение структуры для TempUser пользовательской структуры. Это также не позволяет преобразовать объект в принятые типы данных Firestore.

 public struct TempUser: Codable {
    let uid: String?
    let username: String?
    let profileImageURL: String?
    let fullname: String?
    
    var dictionary: [String: Any] {
        let data = (try? JSONEncoder().encode(self)) ?? Data()
        return (try? JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [String: Any]) ?? [:]
    }
    
    enum CodingKeys: String, CodingKey {
        case uid
        case username
        case profileImageURL
        case fullname
    }
}
 

Вызывающий функцию

 ConsolidationDataService.instance.createNewBucket(bucket: uploadedBucket, user: self.user!, 
    collections: self.collectionsBeingAddedToArray) { (completed) in
        if completed {
            print("Finished.")
            self.showAlert()
        }
}
 

где collectionsBeingAddedToArray имеет тип [String] и user имеет тип UserDictionary , который является пользовательской структурой для пользовательского объекта.

Ответ №1:

Для оценки второго примера недостаточно информации. В первом случае TempUser экземпляр struct должен быть преобразован в [String: Any] словарь.

 
    let encodedTempUserA: [String: Any]
    let encodedTempUserB: [String: Any]
    do {
        encodedTempUserA = try Firestore.Encoder().encode(tempUserA)
        encodedTempUserB = try Firestore.Encoder().encode(tempUserB)
    } catch {
        handleEncodingError(error)
        return
    }

    let consolidatedBucket = [
            "consolidatedBucketId": consolidatedId,
            "bucketTitle": bucket.bucketTitle,
            "creatorUsername": user.username,
            "creatorUid": user.uid,
            "bucketLogCount": 1,
            "completedCount": 0,
            "uncompletedCount": 1,
            "bucketIds": [bucket.bucketId],
            "bucketImages": [],
            "collectionIds": [],
            "tempUserA": encodedTempUserA,
            "tempUserB": encodedTempUserB
        ] as [String : Any]