Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Decoding Arrays results in type mismatch #51

Open
vikdenic opened this issue Aug 30, 2018 · 5 comments
Open

Decoding Arrays results in type mismatch #51

vikdenic opened this issue Aug 30, 2018 · 5 comments

Comments

@vikdenic
Copy link

vikdenic commented Aug 30, 2018

My data structure looks like this. "humans" is a dictionary of keys whose values are the dictionary of a human. And that human can have a dictionary of keys whose values are the dictionary of a dog.

  "humans" : {
    "abc123" : {
      "name" : "Vince",
      "pets" : [ {
        "animal" : "dog",
        "name" : "Clifford"
      }, {
        "animal" : "fish",
        "name" : "Nemo"
      } ]
    },
    "xyz789" : {
      "name" : "Jack"
    }
  }

And so my Swift structs looks like this to match it:

struct Human: Codable {
    var name: String!
    var pets: [Pet]?
}

struct Pet: Codable {
    var name: String!
    var animal: Animal!
}

enum Animal: String, Codable {
    case cat
    case dog
    case fish
}

I try to decode like this:
let human = try FirebaseDecoder().decode([Human].self, from: value)

But I am getting the following error when trying to encode objects that have arrays of some object:

typeMismatch(Swift.Array<Any>, Swift.DecodingError.Context(codingPath: [], debugDescription: "Not an array", underlyingError: nil))

How can I properly encode a dictionary's values as an array?

@vikdenic vikdenic changed the title Encoding Arrays results in type mismatch Decoding Arrays results in type mismatch Aug 31, 2018
@DevAndArtist
Copy link

DevAndArtist commented Sep 2, 2018

I have no idea how this library works exactly, plus I'm just a passenger on this repo, but the above snapshot which is like a json does not work as an array. The humans key contains key value pairs instead of just values.

"humans": {
    "key" : { ... },
    ...
  }
}

Instead it should be:

"humans": [
    { ... },
    ...
  ]
}

Therefore the following 'might' work:

let dictionary = try FirebaseDecoder().decode([String: Human].self, from: value)
let humans = dictionary.map { $0.value } // no order preserved

@vikdenic
Copy link
Author

vikdenic commented Sep 2, 2018

@DevAndArtist So Firebase does not allow values to be arrays; everything must be a dictionary. Otherwise I would have designed the data model according to your response.

Instead to solve this, I simply pass the 'values' of the dictionary / snapshot.value to the decoding function:

guard let value = snapshot.value as? [String : Any] else { return }

do {
  let humans = try FirebaseDecoder().decode([Human].self, from: Array(value.values))
} catch let decodeError {
  print(decodeError)
}

The magic is in passing Array(value.values) instead of just value

@DevAndArtist
Copy link

DevAndArtist commented Sep 2, 2018

Ah sorry, you were referring to the old database, while I had Firestore in mind when I wrote my reply which does support arrays and maps.

@alickbass
Copy link
Owner

alickbass commented Sep 13, 2018

@vikdenic Firebase does allow array as values. You can save a NSArray to the firebase. Try it in some test project

@AmitaiB
Copy link

AmitaiB commented Mar 22, 2022

Also read https://firebase.googleblog.com/2014/04/best-practices-arrays-in-firebase.html for some of the rationale in Google's choice.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants