17

I'm still in the learning process of Go but am hitting a wall when it comes to JSON response arrays. Whenever I try to access a nested element of the "objects" array, Go throws (type interface {} does not support indexing)

What is going wrong and how can I avoid making this mistake in the future?

package main    

import (
        "encoding/json"
        "fmt"
)    

func main() {
        payload := []byte(`{"query": "QEACOR139GID","count": 1,"objects": [{"ITEM_ID": "QEACOR139GID","PROD_CLASS_ID": "BMXCPGRIPS","AVAILABLE": 19}]}`)
        var result map[string]interface{}
        if err := json.Unmarshal(payload, &result); err != nil {
            panic(err)
        }        

        fmt.Println(result["objects"]["ITEM_ID"])    

}

http://play.golang.org/p/duW-meEABJ

edit: Fixed link

3
  • your example works for me ... Commented Jun 24, 2014 at 3:38
  • @fabrizioM, the example at play.golang.org is not the same as the code listed in the question. Commented Jun 24, 2014 at 4:01
  • Fixed. Sorry about that. Commented Jun 24, 2014 at 15:49

2 Answers 2

28

As the error says, interface variables do not support indexing. You will need to use a type assertion to convert to the underlying type.

When decoding into an interface{} variable, the JSON module represents arrays as []interface{} slices and dictionaries as map[string]interface{} maps.

Without error checking, you could dig down into this JSON with something like:

objects := result["objects"].([]interface{})
first := objects[0].(map[string]interface{})
fmt.Println(first["ITEM_ID"])

These type assertions will panic if the types do not match. You can use the two-return form, you can check for this error. For example:

objects, ok := result["objects"].([]interface{})
if !ok {
    // Handle error here
}

If the JSON follows a known format though, a better solution would be to decode into a structure. Given the data in your example, the following might do:

type Result struct {
    Query   string `json:"query"`
    Count   int    `json:"count"`
    Objects []struct {
        ItemId      string `json:"ITEM_ID"`
        ProdClassId string `json:"PROD_CLASS_ID"`
        Available   int    `json:"AVAILABLE"`
    } `json:"objects"`
}

If you decode into this type, you can access the item ID as result.Objects[0].ItemId.

Sign up to request clarification or add additional context in comments.

4 Comments

I literally just typed up the same answer. Delayed because I had to carry in the groceries :)
For future reference, here is a working play example: play.golang.org/p/iYjrB-72u5
Thanks for this insight on working with nested JSON structure!
HI James Henstridge, type Example struct { text []string } type Result struct { Query string Count int Objects []struct { ItemId string } }
0

For who those might looking for similar solution like me, https://github.com/Jeffail/gabs provides better solution.

I provide the example here.

package main

import (
    "encoding/json"
    "fmt"

    "github.com/Jeffail/gabs"
)

func main() {
    payload := []byte(`{
        "query": "QEACOR139GID",
        "count": 1,
        "objects": [{
            "ITEM_ID": "QEACOR139GID",
            "PROD_CLASS_ID": "BMXCPGRIPS",
            "AVAILABLE": 19, 
            "Messages": [ {
                    "first": {
                        "text":  "sth, 1st"
                    }
                },
                {
                        "second": {
                        "text": "sth, 2nd"
                    }
              }
            ]
        }]
    }`)

    fmt.Println("Use gabs:")
    jsonParsed, _ := gabs.ParseJSON(payload)
    data := jsonParsed.Path("objects").Data()
    fmt.Println("  Fetch Data: ")
    fmt.Println("    ", data)
    children, _ := jsonParsed.Path("objects").Children()
    fmt.Println("  Children Array from \"Objects\": ")
    for key, child := range children {
        fmt.Println("    ", key, ": ", child)
        children2, _ := child.Path("Messages").Children()
        fmt.Println("    Children Array from \"Messages\": ")
        for key2, child2 := range children2 {
            fmt.Println("      ", key2, ": ", child2)
        }
    }
}

Comments

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.