为什么将 Firestore querySnapshot 转换为 compactMap returns 为空的自定义对象,尽管 querySnapshot 包含文档?

Why converting a Firestore querySnapshot into custom objects with compactMap returns empty although the querySnapshot contains documents?

Screenshot of a Firestore Document

我正在使用 Swift、Xcode 和 Firestore 数据库。 我用字典创建了一个 TableView 和一个自定义对象 Class (MediumSample),并想加载我的 Firestore 文档并在 TableView 中显示它们。

文档(屏幕截图中的示例)已从 Firestore 正确加载,但无法转换为对象。从 compactMap 返回的对象列表总是空的。

这是我的代码片段。如果有人暗示出了什么问题,那就太好了。

自定义对象Class(简体):

import Foundation
import FirebaseFirestore

protocol MediumSampleDocumentSerializable {
    init?(dictionary: [String:Any])
}

struct MediumSample {

    var id: String
    var field_t: String
    var field_i: Int64
    var field_b1: Bool
    var field_b2: Bool
    var field_g: FirebaseFirestore.GeoPoint
    var field_d: Date
    var field_a: [String]
    var usecase: String


    var dictionary: [String:Any] {
         return [
             "id": id,
             "field_t": field_t,
             "field_i": field_i,
             "field_b1": field_b1,
             "field_b2": field_b2,
             "field_g": field_g,
             "field_d": field_d,
             "field_a": field_a,
             "usecase": usecase
         ]
     }

}

extension MediumSample: MediumSampleDocumentSerializable {
    init?(dictionary: [String:Any]) {
        guard let id = dictionary ["id"] as? String,
        let field_t = dictionary ["field_t"] as? String,
        let field_i = dictionary ["field_i"] as? Int64,
        let field_b1 = dictionary ["field_b1"] as? Bool,
        let field_b2 = dictionary ["field_b2"] as? Bool,
        let field_g = dictionary ["field_g"] as? FirebaseFirestore.GeoPoint,
        let field_d = dictionary ["field_d"] as? Date,
        let field_a = dictionary ["field_a"] as? [String],
        let usecase = dictionary ["usecase"] as? String else {return nil}

        self.init (id: id, field_t: field_t, field_i: field_i, field_b1: field_b1, field_b2: field_b2, field_g: field_g, field_d: field_d, field_a: field_a, usecase: usecase)
    }

}

声明数据库和数组并调用加载函数:

import UIKit
import FirebaseFirestore

class MediumTableViewController: UITableViewController {

    //MARK: Properties

    var db: Firestore!
    var mediumsamples = [MediumSample]()

    override func viewDidLoad() {
        super.viewDidLoad()

        db = Firestore.firestore()
        loadMediumSamples()

    }

用于加载 Firestore 文档以填充数组的函数:

    private func loadMediumSamples() {

               //run the Firestore query
               db.collection(Constants.MEDIUMS).whereField("usecase", isEqualTo: Constants.USECASE)
                   .getDocuments() { querySnapshot, err in
                       if let err = err {
                           print("Error getting documents: \(err)")
                       } else {

                        //initialise an array of medium objects with Firestore data snapshots
                        self.mediumsamples = querySnapshot!.documents.compactMap({MediumSample(dictionary: [=13=].data())})

                        //fill the tableView
                        DispatchQueue.main.async {
                            self.tableView.reloadData()
                            print(self.mediumsamples)
                        }

                        print("Mediums List", self.mediumsamples) // This line returns: Mediums List []

                        print("Mediums List size", (self.mediumsamples.count)) // This line returns: Mediums List size 0

                        for document in querySnapshot!.documents {
                            print("\(document.documentID) => \(document.data())") // This line returns the snapshot documents correctly!

                        }
                       }
               }
    }

截图对象添加方法如下:

    func addMediumSamples() {

        let currentDateTime = Date()
        let location = FirebaseFirestore.GeoPoint(latitude: 0, longitude: 0)
        let mediumsample = MediumSample(id: "an id", field_t: "field_t", field_i: 10, field_b1: true, field_b2: false, field_g: location, field_d: currentDateTime, field_a: [Constants.SAMPLE_DEV], usecase: Constants.SAMPLE_DEV)

        var ref: DocumentReference? = nil
        ref = self.db.collection(Constants.MEDIUMS).addDocument(data: mediumsample.dictionary) {
            error in
            if let error = error {
                print("Error writing city to Firestore: \(error)")
            } else {
                print("Document added with id : \(ref!.documentID)")
            }
        }

    }

问题出在MediumSample 结构 中,在field_d 类型(日期)中。 Cloud Firestore 数据库中该字段的类型是 Timestamp.

MediumSample 结构中的字段 "field_d" 需要 Date.

类型的值

你可以把type改成FirebaseFirestore.Timestamp,也可以在mapping的时候和passing之前转成Date到 MediumSample。

例如。在 Swift

中将时间戳转换为日期

let date = timestamp.dateValue()