0

I download a JSON file from my database which returns the following string:

["ingredients": asdasdasd, 
"price": 14, 
"_id": 
    {
     "$oid" = 5e8e3706f00ca80f251485c3;
    }, 
"category": sadad,
 "available": Disponibile,
 "name": asdadasd]

I then convert this string to data to then convert it to a Dictionary<String, Any>

   if let myData = responseString.data(using: .utf8) {
        do {
            let myArray = try (JSONSerialization.jsonObject(with: myData) as? [Dictionary<String, Any>])!
            completion(myArray, nil)
        } catch let error as NSError {
            print("error:" + String(describing: error))
            completion(nil, error)
        }
    }

This works perfectly fine, as I can get, let's say, the price parameter doing myArray["price"].

The problem arises when I try to get the Id parameter, as when I do myArray["_id"] I get:

{
    "$oid" = 5e8e370af00ca80f251485cf;
}

I would like to directly get the ID parameter, and I can't parse this value to JSON as it is not in JSON format. At the moment I am fixing the issue by manipulating this string replacing the = with :, removing the ; and other nasty stuff, but I am sure there is a more efficient way to solve the issue.

mkrieger1
  • 19,194
  • 5
  • 54
  • 65
Riccardo Perego
  • 203
  • 2
  • 9

2 Answers2

0

myArray["_id"] is a Dictionary in your myArray.So you have to convert your myArray["_id"] to dictionary and then you can access the id. try this

let id =  (myArray["_id"] as Dictionary ?? [:])["$oid"] as? String ?? ""
Dilan
  • 2,610
  • 7
  • 23
  • 33
0

What you've posted looks like debugger print output, not JSON from your server. I'm going to assume that your JSON actually looks like this:

[ 
  {
    "ingredients": "asdasdasd", 
     "price": 14, 
     "_id": {
       "$oid": "5e8e3706f00ca80f251485c3"
      }, 
     "category": "sadad",
     "available": "Disponibile",
     "name": "asdadasd"
  } 
]

Given that, you could use a model struct like

struct Recipe: Codable {
    let ingredients: String
    let price: Int
    let id: ID
    let category, available, name: String

    enum CodingKeys: String, CodingKey {
        case ingredients, price
        case id = "_id"
        case category, available, name
    }
}

struct ID: Codable {
    let oid: String

    enum CodingKeys: String, CodingKey {
        case oid = "$oid"
    }
}

typealias Recipes = [Recipe]

to parse it using

do {
   let recipes = try JSONDecoder(Recipes.self, from: myData)

   let firstOid = recipe.first?.id.oid
} catch {
   print(error)
}

That said, I would recommend avoiding generic names like myArray for your variables.

Also, when retrieving JSON data from your server, it's not necessary to first convert them to a String and then back to Data before passing it to the JSON parser - simply pass the raw server data along.

Gereon
  • 17,258
  • 4
  • 42
  • 73
  • Why would you suggest using a struct instead of a class? – Riccardo Perego Apr 10 '20 at 15:11
  • Because structs are immutable value types, and that is usually how you want to treat data retrieved from your server. [This answer](https://stackoverflow.com/a/24232845/1918561) has a pretty good explanation on how to choose. – Gereon Apr 10 '20 at 15:21