Reputation: 1106
I am writing an endpoint to return data for Geckoboard, it excepts a format like so:
{
"item": [
{
"value": "274057"
},
[
"38594",
"39957",
"35316",
"35913",
"36668",
"45660",
"41949"
]
]
}
"item"
is an array of varying structures. How would I represent this data in Go?
Note: this is not on how I would unmarshal this, I need to generate this format.
Upvotes: 1
Views: 528
Reputation: 418585
There is an easy way to create a value of some data structure where you know the JSON output you want to generate/duplicate:
Take the output you want to generate, and unmarshal it into a map[string]interface{}
. You will get a map value which when you marshal will result in your desired output. When you unmarshal an expected output, you can inspect the result map value to know what you need to create in order for your expected output.
This works in your case too. Here is the code:
var m map[string]interface{}
err := json.Unmarshal([]byte(input), &m)
if err != nil {
panic(err)
}
fmt.Printf("%+v\n", m)
res, err := json.MarshalIndent(m, "", " ")
if err != nil {
panic(err)
}
fmt.Println(string(res))
Where input
is your JSON input:
const input = `{
"item": [
{
"value": "274057"
},
[
"38594",
"39957",
"35316",
"35913",
"36668",
"45660",
"41949"
]
]
}`
This program generates the same output as your required output (or input):
map[item:[map[value:274057] [38594 39957 35316 35913 36668 45660 41949]]]
{
"item": [
{
"value": "274057"
},
[
"38594",
"39957",
"35316",
"35913",
"36668",
"45660",
"41949"
]
]
}
Try the complete application on the Go Playground.
Obviously it has a key "item"
, its value's type:
fmt.Printf("%T\n", m["item"]); // Prints []interface{}
So it's a slice. It has 2 values, their types:
fmt.Printf("%T\n", m["item"].([]interface{})[0]); // map[string]interface{}
fmt.Printf("%T\n", m["item"].([]interface{})[1]); // []interface{}
So the slice contains 2 values:
"value" : "274057"
pair)Here is the Go code to reproduce the same map value:
m := map[string]interface{}{
"item": []interface{}{
map[string]interface{}{"value": "274057"},
[]interface{}{"38594", "39957", "35316", "35913", "36668", "45660", "41949"},
},
}
Marshaling this produces the same JSON output.
Upvotes: 1
Reputation:
This stuff is easier than you might think. It's just not that well documented for the casual reader. I would recommend ffjson
over normal json
tho. It's made up in such a manner that you don't need to change your syntax other than the library name.
It's easy as this:
type User struct {
Id int `json:'id'`
Name string `json:name`
SomeId1 int `json:some_id_1`
SomeId2 int `json:some_id_2`
SomeId3 int `json:some_id_3`
SomeId4 int `json:some_id_4`
}
item := map[string]User{}
for i := 0; i < 10; i++ {
item[strconv.itoa(i)] = User{i, "Username X", 38393, 29384, 12393, 123981}
}
buf, err := ffjson.Marshal(&item)
The downside of structs (even in ffjson
still) is that reflection
will always be used, which, in times that you're in need of high performance, you will waste a lot of CPU cycles. ffjson
is 2-3 times faster than normal json
when you keep it to maps. This way the library can compile every data-structure you marshal and re-use it instead of constantly inspecting the data-integrity/structure with reflect
.
Upvotes: 1