【问题标题】:How do I loop through a firestore document that has an array of maps?如何遍历具有地图数组的 Firestore 文档?
【发布时间】:2020-07-12 07:07:52
【问题描述】:

我主要使用字典,因为我是新手,但这里我们有一个嵌入式结构,我需要循环访问。有了这个,我需要能够在 UITableView 中填充扩展单元格。

我的结构如下所示:

struct Complain: Codable {
    let eMail, message, timeStamp, userEmail: String
    let status: Bool
    let planDetails: PlanDetails

    enum CodingKeys: String, CodingKey {
        case eMail = "E-mail"
        case message = "Message"
        case timeStamp = "Time_Stamp"
        case userEmail = "User_Email"
        case status, planDetails
    }
}

// MARK: - PlanDetails
struct PlanDetails: Codable {
    let menuItemName: String
    let menuItemQuantity: Int
    let menuItemPrice: Double
}

我的查询如下所示:

db.collection("Feedback_Message").getDocuments() { documentSnapshot, error in
            if let error = error {
                print("error:\(error.localizedDescription)")
            } else {
                for document in documentSnapshot!.documents {
                    let eMail = document.get("E-mail")
                    let message = document.get("Message")
                    let timeStamp = document.get("Time_Stamp")
                    let userEmail = document.get("User_Email")
                    let planDetails = document.get("planDetails")

                    // how to loop through planDetails
            }
        }

我已经走到这一步了:

db.collection("Feedback_Message").getDocuments() { documentSnapshot, error in
            if let documentSnapshot = documentSnapshot {
                for document in documentSnapshot.documents {
                    guard let planDetails = document.get("planDetails") as? [[String : Any]] else {
                        let email = document.get("E-mail")
                        let message = document.get("Message")
                        let timeStamp = document.get("Time_Stamp")
                        let userEmail = document.get("User_Email")
                        let status = false
                    }
                    for plan in planDetails {
                        if let menuItemName = plan["menuItemName"] as? String {
                            // not sure I populate the menuItemsName, menuItemsQuantity and menuItemsPrice within the array
                        }
                    }

                }
            }
        }

更新 2:

最终查询:这终于按预期工作了。但我无法填充正在扩展的单元格。

db.collection("Feedback_Message").getDocuments() { documentSnapshot, error in
            if let documentSnapshot = documentSnapshot {
                for document in documentSnapshot.documents {
                    guard let planDetails = document.get("planDetails") as? [[String : Any]],
                        let email = document.get("E-mail") as? String,
                        let message = document.get("Message") as? String,
                        let timeStamp = document.get("Time_Stamp") as? String,
                        let userEmail = document.get("User_Email") as? String,
                        let status = document.get("status") as? Bool else {
                            continue
                        }
                    for plan in planDetails {
                        guard let menuItemName = plan["menuItemName"] as? String,
                            let menuItemQuantity = plan["menuItemQuantity"] as? Int,
                            let menuItemPrice = plan["menuItemPrice"] as? Double else {
                                continue
                        }
                        let planDetails = PlanDetails(menuItemName: menuItemName, menuItemQuantity: menuItemQuantity, menuItemPrice: menuItemPrice)
                        let complaint = Complain(eMail: email, message: message, timeStamp: timeStamp, userEmail: userEmail, status: status, planDetails: planDetails)
                        self.messageArray.append(complaint)
                        print(self.messageArray)
                    }
                }
            }
        }

【问题讨论】:

    标签: swift uitableview google-cloud-firestore


    【解决方案1】:

    编辑

    // OPTION 1 - FULL REQUIREMENT
    db.collection("Feedback_Message").getDocuments() { documentSnapshot, error in
        if let documentSnapshot = documentSnapshot {
            for document in documentSnapshot.documents {
                // all of these properties are required to parse a single document
                guard let planDetails = document.get("planDetails") as? [[String : Any]],
                    let email = document.get("E-mail") as? String,
                    let message = document.get("Message") as? String,
                    let timeStamp = document.get("Time_Stamp") as? String,
                    let userEmail = document.get("User_Email") as? String,
                    let status = document.get("status") as? Bool else {
                        continue // continue this loop
                }
                for plan in planDetails {
                    // all of these properties are required to instantiate a struct
                    guard let name = plan["menuItemName"] as? String,
                        let price = plan["menuItemName"] as? Double,
                        let quantity = plan["menuItemQuantity"] as? Int else {
                            continue // continue this loop
                    }
                    let plan = PlanDetails(menuItemName: name, menuItemQuantity: quantity, menuItemPrice: price)
                    // then you will likely append this plan to an array 
                }
            }
        }
    }
    
    // OPTION 2 - PARTIAL REQUIREMENT
    db.collection("Feedback_Message").getDocuments() { documentSnapshot, error in
        if let documentSnapshot = documentSnapshot {
            for document in documentSnapshot.documents {
                // all of these properties are required to parse a single document
                guard let planDetails = document.get("planDetails") as? [[String : Any]],
                    let email = document.get("E-mail") as? String,
                    let message = document.get("Message") as? String else {
                        continue // continue this loop
                }
                // these properties are not required
                let timeStamp = document.get("Time_Stamp") as? String // optional (can be nil)
                let userEmail = document.get("User_Email") as? String // optional (can be nil)
                let status = document.get("status") as? Bool ?? false // not optional because it has a default value of false
                for plan in planDetails {
                    // all of these properties are required to instantiate a struct
                    guard let name = plan["menuItemName"] as? String,
                        let price = plan["menuItemName"] as? Double,
                        let quantity = plan["menuItemQuantity"] as? Int else {
                            continue // continue this loop
                    }
                    let plan = PlanDetails(menuItemName: name, menuItemQuantity: quantity, menuItemPrice: price)
                    // then you will likely append this plan to an array
                }
            }
        }
    }
    

    还有很多其他方法可以做到这一点,这些只是其中的几种。例如,您可以使用 [String: Any] 字典本身来实例化结构。

    【讨论】:

    • 嗨 - 对不起,我的新手真的在这里展示;我有点明白你的意思,并在原始帖子的底部更新了我的代码。我有一个包含结构类型 Complaint 的 messageArray,但我不确定如何填充每个结构的嵌入部分并循环重复。
    • @BVB09 每个人的新手都在某个地方出现。我编辑了我的答案。如果您有任何问题,请告诉我。
    • 谢谢。我学到了很多。但是,我无法填充 TableView 中的扩展单元格。我发布了 2 个错误的屏幕截图。我不确定我在那里做错了什么。
    • 你想如何填充表格? messageArrayComplaint 的数组。表格中的每一行应该代表一个投诉,还是每个投诉都应该代表一个部分,每个部分中的行是什么?
    • 部分的数量将是开始时的投诉总数,即messageArray.count。当用户点击投诉部分时,相应的 planDetails 行将在下方打开。我发现这个视频表明了我想要实现的目标:youtube.com/watch?v=ClrSpJ3txAs&t=650s。所以每个部分(在顶部)都是一个投诉,它下面的行应该是 menuItems、menuItemPrice 和 menuItemQuantity 的详细信息。
    【解决方案2】:

    我终于弄清楚了问题所在。与我设置结构的方式以及填充数组的方式有关。

    正确的方法就是这样,即 planDetails 需要转换为数组:

    struct Complain: Codable {
        let eMail, message, timeStamp, userEmail: String
        let status: Bool
        let planDetails: [PlanDetails]
    
        enum CodingKeys: String, CodingKey {
            case eMail = "E-mail"
            case message = "Message"
            case timeStamp = "Time_Stamp"
            case userEmail = "User_Email"
            case status, planDetails
        }
    }
    
    // MARK: - PlanDetails
    struct PlanDetails: Codable {
        let menuItemName: String
        let menuItemQuantity: Int
        let menuItemPrice: Double
    }
    

    然后我需要遍历每个计划项,将其添加到数组中,然后将数组添加到顶层 Complain:

    db.collection("Feedback_Message").getDocuments() { documentSnapshot, error in
                if let documentSnapshot = documentSnapshot {
                    for document in documentSnapshot.documents {
                        guard let planDetails = document.get("planDetails") as? [[String : Any]],
                            let email = document.get("E-mail") as? String,
                            let status = document.get("status") as? Bool else {
                                continue
                            }
    
                        for plan in planDetails {
                            guard let menuItemName = plan["menuItemName"] as? String,
                            let menuItemQuantity = plan["menuItemQuantity"] as? Int else {
                                    continue
                            }
                            let singlePlan = PlanDetails(menuItemName: menuItemName, menuItemQuantity: menuItemQuantity)
                            self.planDetailsArray.append(singlePlan)
                        }
                        let complain = Complain(eMail: email, status: status, planDetails: self.planDetailsArray)
                        self.planDetailsArray.removeAll()
                        self.messageArray.append(complain)
                    }
                }
                // Print the main array or load table
                }
            }
    

    bsod 的答案仍然是正确答案,因为没有他的帮助,我无法得出他的结论。

    【讨论】:

      猜你喜欢
      • 2022-01-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-11-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多