alickbass/CodableFirebase

Error on Parsing [String: Any]

asher636 opened this issue · 11 comments

Hi,

Thanks for such an awesome library.

I am using this in my project, but I have a following issue whenever I add a 'var fieldValues: [String: Any]' in my model class, it keep showing Type 'abc' does not conform to protocol 'Decodable'/'Encodable'. So how would you suggest to make Any decodable?

Can you please guide me on this? Thanks!

Hi! Any does not conform to Codable, so you can't have a type [String: Any]. You could use [String: Codable] though and it should work

Thanks I will try that !

Hi, I have the same issue. Unfortunately it doesn't work, and neither: var fieldValues:Codable. Have you found a solution for this ?

Hi @CureleaAndrei, I actually followed this tutorial:
https://medium.com/grand-parade/parsing-fields-in-codable-structs-that-can-be-of-any-json-type-e0283d5edb
If you need to ask me any thing about it you're welcome. Thanks.

Hi @alickbass, I tried your suggestion but it didn't seem to work.

var fieldValues: [String: Codable]?

It says Type 'Sample' does not conform to protocol 'Decodable'. I want to parse a map object from Firebase, and the link I posted in my last comment won't work with multiple entries in the map.

Do you have some other suggestion? Thanks.

Can you post your Sample struct/class? As the error says it has to conform to Decodable. You need to make sure that all properties of the Sample struct/class conform to Decodable as well.

As soon as I remove var fieldValues: [String: Codable]? it works. So there is some problem with this Codable datatype. Below is my struct code:

struct NewJob: Decodable {
    var id: String?
    var address: String?
    var assignee: String?
    var contractor: String?
    var fieldValues: [String: Codable]?
}

You need to specify what you’re expecting to decode. You can’t just say Codable it needs to be a specific concrete type.

Like maybe a User that conforms to Codable or more NewJob s

I see, but that is the problem. I don't know what type of data my Firestore fieldValues can have. Below I attach a screenshot of my Firestore

firebasedatastruct

To overcome this I followed this link: https://medium.com/grand-parade/parsing-fields-in-codable-structs-that-can-be-of-any-json-type-e0283d5edb, it was working for one item in fieldValues but now as I have multiple it doesn't work.

The article you attached is perfect should have your code working, except the author of the article missed that null is a JSONValue as well and in your Firestore its obvious that you have null objects as well. So if you do the following things should work:

public enum JSONValue: Decodable {
    case string(String)
    case int(Int)
    case double(Double)
    case bool(Bool)
    case object([String: JSONValue])
    case array([JSONValue])
    case null

    public init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        self = try ((try? container.decode(String.self)).map(JSONValue.string))
            .or((try? container.decode(Int.self)).map(JSONValue.int))
            .or((try? container.decode(Double.self)).map(JSONValue.double))
            .or((try? container.decode(Bool.self)).map(JSONValue.bool))
            .or((try? container.decode([JSONValue].self)).map(JSONValue.array))
            .or((try? container.decode([String: JSONValue].self)).map(JSONValue.object))
            .or(container.decodeNil() ? JSONValue.null : nil)
            .resolve(with: DecodingError.typeMismatch(JSONValue.self, DecodingError.Context(codingPath: container.codingPath, debugDescription: "Not a JSON")))
    }
}

struct NewJob: Decodable {
    var id: String?
    var address: String?
    var assignee: String?
    var contractor: String?
    var fieldValues: JSONValue
}

Unfortunately it is not working. Below is the error I get:

typeMismatch(Nava.JSONValue, Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "fieldValues", intValue: nil)], debugDescription: "Not a JSON", underlyingError: nil))

I think I have to go back to manual parsing 😞.

UPDATE:
Never mind, I finally figured it out. I have a timestamp on Firestore, whereas I was not handling it in decoding logic. Finally it is fixed! Thanks!  🥳