【问题标题】:Why converting a Firestore querySnapshot into custom objects with compactMap returns empty although the querySnapshot contains documents?尽管 querySnapshot 包含文档,为什么使用 compactMap 将 Firestore querySnapshot 转换为自定义对象返回空?
【发布时间】:2020-06-26 02:14:41
【问题描述】:

Screenshot of a Firestore Document

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

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

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

自定义对象类(简化):

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: $0.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)")
            }
        }

    }

【问题讨论】:

  • 正如您所说,您的转换似乎总是返回零。您可以在 Firebase 控制台中截取您的 Firebase 对象之一吗?
  • 嗨 Luka,我创建了一个对象并添加了上面的屏幕截图(在第一句中)。我还添加了我使用的功能。该对象创建成功,但仍然没有在 querySnapshot!.documents.compactMap 中返回。

标签: swift firebase google-cloud-firestore flatmap


【解决方案1】:

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

MediumSample 结构中的字段 "field_d" 需要 Date 类型的值。

您可以将类型更改为 FirebaseFirestore.Timestamp,也可以在映射时和传递给 MediumSample 之前将其转换为 Date

例如。用于在 Swift 中将时间戳转换为日期

让日期 = timestamp.dateValue()

【讨论】:

  • 是的,非常感谢。我正要进入这个解决方案。我通过调试init字典函数发现了它,我看到类型Date总是导致中断返回nil。
猜你喜欢
  • 2020-10-24
  • 2018-09-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-18
  • 2022-01-18
  • 2020-08-23
相关资源
最近更新 更多