How do I loop through a firestore document that has an array of maps?

一世执手 提交于 2020-04-30 11:12:31

问题


I mostly work with dictionaries since I am fairly new but here we have an embedded struct that I need to loop through. With this, I need to be able to populate expanding cells in UITableView.

My struct looks like this:

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
}

And my query looks like this:

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
            }
        }

I have gotten this far:

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
                        }
                    }

                }
            }
        }

UPDATE 2:

Final query: This is finally working as expected. But am not able to populate the expanding cells.

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)
                    }
                }
            }
        }

回答1:


EDIT

// 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

            }

        }

    }

}

There are a number of other ways you can do this, these are just a couple. For example, you can instantiate the struct with the [String: Any] dictionary itself.




回答2:


I finally figured out what the problem was. Had to do with the way I setup the struct and how I populate the array.

Right way is as such i.e. the planDetails need to be cast as an array:

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
}

And then I need to iterate through each plan item, add it to the array and then add the array to the top level 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's answer stays as the correct answer because without his help, I would not have been able to arrive at his conclusion.



来源:https://stackoverflow.com/questions/60955542/how-do-i-loop-through-a-firestore-document-that-has-an-array-of-maps

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!