0

I am getting an empty array back from firestore. Specifically from the sub model "Coor" inside of "EventModel".

Data Model:

struct EventModel: Identifiable, Codable {
    var id: String
    var isLive: Bool
    var coors: [Coor]
    var eventCenterCoor: [Double]
    var hostTitle: String
    var eventName: String
    var eventDescription: String
    var isEventPrivate: Bool
    var eventGuestsJoined: [String]
    var eventEndDate: String
    
    private enum CodingKeys: String, CodingKey {
        case id
        case isLive
        case coors
        case eventCenterCoor
        case hostTitle
        case eventName
        case eventDescription
        case isEventPrivate
        case eventGuestsJoined
        case eventEndDate
    }
}

struct Coor: Identifiable, Codable {
    var id = UUID()
    var coorDoubles: [Double]
    
    private enum CodingKeys: String, CodingKey {
        case coorDoubles
    }
}

Firestore request:

    public func getEventData(completion: @escaping (_ eventModel: [EventModel]) -> Void) {
        var eventRef: [EventModel] = []
        self.isLoading = true
        self.loadingMess = "Finding events.."
        self.eventsDataCollection.whereField("isLive", isEqualTo: true)
            .getDocuments { (document, error) in
            if let document = document, error == nil {
                for doc in document.documents {
                    let data = doc.data()
                    let id = data["id"] as? String ?? ""
                    let isLive = data["isLive"] as? Bool ?? false
                    let coors = data["coors"] as? [Coor] ?? []
                    let eventCenterCoor = data["eventCenterCoor"] as? [Double] ?? []
                    let hostTitle = data["hostTitle"] as? String ?? ""
                    let eventName = data["eventName"] as? String ?? ""
                    let eventDescription = data["eventDescription"] as? String ?? ""
                    let isEventPrivate = data["isEventPrivate"] as? Bool ?? false
                    let eventGuestsJoined = data["eventGuestsJoined"] as? [String] ?? []
                    let eventEndDate = data["eventEndDate"] as? String ?? ""
                    
                    eventRef.append(EventModel(id: id, isLive: isLive, coors: coors, eventCenterCoor: eventCenterCoor, hostTitle: hostTitle, eventName: eventName, eventDescription: eventDescription, isEventPrivate: isEventPrivate, eventGuestsJoined: eventGuestsJoined, eventEndDate: eventEndDate))
                }
                
                completion(eventRef)
            } else if error != nil {
                print(error ?? "Error getting events where 'isLive' == true")
                self.isLoading = false
            }
        }
    }

Here is the firestore data:

enter image description here

Printing "coors" returns an empty array. The empty array is because this line:

let coors = data["coors"] as? [Coor] ?? []

is defaulting to the empty array. This must mean the data type of [Coor] is incorrect?

2
  • 1
    Your Coor type has a property called coor that should be called coorDouble to match your data. Commented Jan 29, 2022 at 8:22
  • @jnpdx true, although does not matter if I cant even get the data in the first place Commented Jan 29, 2022 at 20:24

1 Answer 1

2

You are decoding an array called coorsDouble with this line:

let coorsDouble = data["coorsDouble"] as? [Coor] ?? []

If you look at your data structure, each element is made up of this structure:

{ coolDouble: [Double] }

But, in your Coor model, you have this structure:

struct Coor: Identifiable, Codable {
    var id = UUID()
    var coor: [Double]
    
    private enum CodingKeys: String, CodingKey {
        case coor
    }
}

In order to decode the Coor, you'd need its structure to match. So, change it to:

struct Coor: Identifiable, Codable {
    var id = UUID()
    var coorDouble: [Double]
    
    private enum CodingKeys: String, CodingKey {
        case coorDouble
    }
}

Next, CodingKeys only take effect when using Codable. Right now, you're just trying to cast a dictionary value (of type Any) to Coor, which isn't going to work. In general, I'd say you should use Codable with your entire structure, but if you wanted to avoid it for some reason, you'd need to do this:

//replacing let coorsDouble = data["coorsDouble"] as? [Coor] ?? []
let coorsDoubleArray = data["coorsDouble"] as? [[String:Any]] ?? []
let coorsDouble = coorsDoubleArray.compactMap { item in 
  guard let doublesArray = item["coorDoubles"] as? [Double] else {
    return nil
  } 
  return Coor(coorDoubles: doublesArray)
}
Sign up to request clarification or add additional context in comments.

8 Comments

See edits, clarified the code and specific issue. It is not a naming issue, rather of why is my data defaulting.
I've updated my answer. Didn't realize you weren't actually using Codable at all to decode. Have you considered using the Firestore Swift function for automatic Codable decoding: firebase.google.com/docs/firestore/query-data/…
I use firestoreswift for setting the data, but I am getting multiple documents and I think you can only use firestoreswift for getting a single document
In theory I could get all the doc ids I want and call getdoc everytime and use firestoreswift but that seems more costly/less efficient.
You'd have to wrap the call in a do/try/catch block. Or, use try? instead of try
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.