5

I'm new to the golang and I have problem while reading the nested JSON response.

var d interface{}
json.NewDecoder(response.Body).Decode(&d)
test :=d["data"].(map[string]interface{})["type"]

response.Body looks like this

{
    "links": {
      "self": "/domains/test.one"
    },
    "data": {
        "type": "domains",
        "id": "test.one",
        "attributes": {
            "product": " Website",
            "package": "Professional",
            "created_at": "2016-08-19T11:37:01Z"
        }
    }
}

The Error I'm getting is this:

invalid operation: d["data"] (type interface {} does not support indexing)
Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
Rohit Kumar
  • 669
  • 3
  • 9
  • 22

3 Answers3

18

d is of type interface{}, so you cannot index it like d["data"], you need another type assertion:

test := d.(map[string]interface{})["data"].(map[string]interface{})["type"]
fmt.Println(test)

Then it will work. Output will be "domains". See a working example on the Go Playground.

Also note that if you declare d to be of type map[string]interface{}, you can spare the first type assertion:

var d map[string]interface{}
if err := json.NewDecoder(response.Body).Decode(&d); err != nil {
    panic(err)
}
test := d["data"].(map[string]interface{})["type"]
fmt.Println(test)

Output is the same. Try this one on the Go Playground.

If you need to do these and similar operations many times, you may find my github.com/icza/dyno library useful (whose primary goal is to aid working with dynamic objects).

icza
  • 389,944
  • 63
  • 907
  • 827
  • Tip for newbies like me: To understand why this code works, one should understand how `Decode` works, which is related to `unmarshal`. The `json.Unmarshal` doc explains how it stores data. – starriet Feb 14 '22 at 09:02
0

You need some tricks to handle your situation.
Like using reflect and you may ref Marshall&&UnMarshall code about bson.M in golang mongo driver mgo

code sample using reflect decode nested as following:

package main

import (
    "encoding/json"
    "fmt"
    "reflect"
)

func main() {
    keys := []string{"hello", "world", "dude", "kind", "cool"}
    a := make(map[string]interface{})
    a[keys[4]] = "perfect"
    b := make(map[string]interface{})
    b[keys[3]] = a
    c := make(map[string]interface{})
    c[keys[2]] = b
    d := make(map[string]interface{})
    d[keys[1]] = c
    e := make(map[string]interface{})
    e[keys[0]] = d
    fmt.Println(e)

    if buf, err := json.Marshal(e); nil == err {
        dd := make(map[string]interface{})
        err = json.Unmarshal(buf, &dd)
        if nil != err {
            fmt.Println("failed", err)
        }

        for k, v := range dd {
            travel(dd, k, v)
        }
        fmt.Println(dd)

    } else {
        fmt.Println("failed marshal")
    }
}

func travel(dd map[string]interface{}, key string, value interface{}) {
    vv := reflect.ValueOf(value)
    switch vv.Kind() {
    case reflect.Map:
        m := value.(map[string]interface{})
        dd[key] = m
        for k, v := range m {
            travel(m, k, v)
        }
    case reflect.String:
        dd[key] = value.(string)
    }
}
Terry Pang
  • 359
  • 1
  • 2
  • 6
  • This question has nothing to do with BSON or Mongo. If you want to reference something for using reflection in this case, you might as well read the source of the `json` package since it's actually relevant. – Adrian Dec 11 '17 at 14:27
  • I recommend to read bson.M cause the questioner said in the comments, *nested interface{}*, and I think bson.M is an example for decode nested interface{} – Terry Pang Dec 12 '17 at 00:06
  • Handling of nesting is simple recursion. JSON does it as well. – Adrian Dec 12 '17 at 00:15
  • I am new to go and familiar with bson.M, sorry to waste your time. – Terry Pang Dec 12 '17 at 00:18
-1

You can do this also:

var inputJson string = "..."

var decoded map[string]map[string]interface{}

json.Unmarshal([]byte(inputJson), &decoded)

test := decoded["data"]["type"]

fmt.Println(test)
// output: domains
Amin Shojaei
  • 5,451
  • 2
  • 38
  • 46