go unmarshaling nested json from http.get - json

I have read Unmarshaling nested JSON objects
but I am still unsure how to handle the json:
{
"input":{
"lat":1234,
"lon":1234
},
"stuff":[
{
"soc":"510950802051011",
"bbox":[
-76.743917,
37.298812,
-76.741184,
37.300357
],
"ccn":"51095",
"name":"James",
"age":"51",
"gf":"Mary",
"state":"NYC",
"pea":"PEA033",
"rea":"REA002",
"rpc":"RPC002",
"vpc":"VPC002"
}
]
}
I would like to only access stuff.ccn, stuff.name
package main
import (
"encoding/json"
"fmt"
)
func main() {
jStr := `{
"input":{
"lat":1234,
"lon":1234
},
"stuff":[
{
"soc":"510950802051011",
"bbox":[
-76.743917,
37.298812,
-76.741184,
37.300357
],
"ccn":"51095",
"name":"James",
"age":"51",
"gf":"Mary",
"state":"NYC",
"pea":"PEA033",
"rea":"REA002",
"rpc":"RPC002",
"vpc":"VPC002"
}
]
}`
type Inner struct {
Key2 []string `json:"ccn"`
Key3 []string `json:"name"`
}
type Outer struct {
Key Inner `json:"stuff"`
}
var cont Outer
json.Unmarshal([]byte(jStr), &cont)
fmt.Printf("%+v\n", cont)
}
I think the issue I am having is with the array.

Your structs needs to follow what you have in JSON. In provided jStr where top level object maps to Outer you seem to have key stuff which is an array of Inner objects. You need to modify your types to reflect that like this:
type Inner struct {
Key2 string `json:"ccn"`
Key3 string `json:"name"`
}
type Outer struct {
Key []Inner `json:"stuff"`
}
This basically says when stuff found take it as array and unmarshall each item as Inner.

You can use json-to-go-struct one to get the go struct for your json.
Or simply use var cont map[string]interface{}

Related

Converting JSON that contains only 1 field of arrays

I'm trying to convert a JSON that contains only 1 field which apparently an array to a complex struct in Golang but unfortunately I'm not getting the data back, instead, I got:
{Result:[]}
Anyone knows why? (code below)
package main
import (
"encoding/json"
"fmt"
)
type Account struct {
AccountId string
}
type Response struct {
Result []Account
}
func main() {
input := []byte(`{
"result": [
{"account_id" : "1"},
{"account_id" : "2"},
{"account_id" : "3"},
]
}
`)
var resp Response
json.Unmarshal(input, &resp)
fmt.Printf("%+v\n", resp)
}
use a explicit tag in your stucture type.
type Account struct {
AccountId string `json:"account_id, omitempty"`
}
If you are a novice, keep in mind the JSON size, if is large then use a stream library (jstream or easyjson etc),
other advice is check nullables or omit when they are empty anyway you can use nullable library like https://github.com/guregu/null
Cheers!

Decoding a slice of maps from a JSON string in Golang

Following the Go by Example: JSON tutorial, I see how to work with a basic JSON string:
package main
import (
"encoding/json"
"fmt"
)
type Response struct {
Page int `json:"page"`
Fruits []string `json:"fruits"`
}
func main() {
str := `{"page": 1, "fruits": ["apple", "peach"]}`
res := Response{}
json.Unmarshal([]byte(str), &res)
fmt.Println(res.Page)
fmt.Println(res.Fruits)
}
// the output looks good here:
// 1
// [apple peach]
I would like to add some complexity to the str data object that I am decoding.
Namely, I would like to add a key with a slice of maps as its value:
"activities": [{"name": "running"}, {"name", "swimming"}]
My script now looks like below example, however, for the life of me, I can not figure out what the correct syntax is in the Response struct in order to get at the values in activities. I know that this syntax isn't correct: Activities []string ... but can not hack my way towards a solution that captures the data I want to display.
package main
import (
"encoding/json"
"fmt"
)
type Response struct {
Page int `json:"page"`
Fruits []string `json:"fruits"`
Activities []string `json:"activities"`
}
func main() {
str := `{"page": 1, "fruits": ["apple", "peach"], "activities": [{"name": "running"}, {"name", "swimming"}]}`
res := Response{}
json.Unmarshal([]byte(str), &res)
fmt.Println(res.Page)
fmt.Println(res.Fruits)
fmt.Println(res.Activities)
}
// the script basically craps out here and returns:
// 0
// []
// []
Thanks for any help!
Use []map[string]string:
type Response struct {
Page int `json:"page"`
Fruits []string `json:"fruits"`
Activities []map[string]string `json:"activities"`
}
playground example
Always check and handle errors.
The example JSON has a syntax error which is corrected in the playground example.
I know this is an old one, but i've recently written utility for generating exact go type from json input and in similar case you could give it a spin: https://github.com/m-zajac/json2go
For this particular example it generates from json:
{"page": 1, "fruits": ["apple", "peach"], "activities": [{"name": "running"}, {"name": "swimming"}]}
go type:
type Object struct {
Activities []struct {
Name string `json:"name"`
} `json:"activities"`
Fruits []string `json:"fruits"`
Page int `json:"page"`
}

Golang: Json from URL as map

What is the best way to extract json from a url i.e. Rest service from Go?
Also it seems most rest client libraries in go force a use of the json.marshall which needs a struct to be used with it.
This doesn't work in the case of unstructured data where you don't fully know what will be coming in. Is there a way to have it all simply come in as a map[string:string]?
Why not to parse it into map[string]string as this code have to do
var d map[string]interface{}
data, err := json.Unmarshal(apiResponse, &d)
You can traverse data in this struct too.
If you suspect, that api response can be not singular object, but the collection of objects, the interface{} also works for arrays.
If you don't know what's coming in a message, you can have several situations.
Message contents that depend on type
Type is usually indicated by some type field. In this case you can use a "union" struct that contains fields from all types:
type Foo struct {
A int
B string
}
type Bar struct {
C int
D string
}
type Message struct {
Type string
Foo
Bar
}
// or this, if you have common fields
type Message struct {
Type string
A int
B string
C int
D string
}
Unmarshal the message into the union struct, dispatch on type, and select the sub-struct.
var m Message
json.Unmarshal(data, &m)
switch m.Type {
case "foo":
...
case "bar":
...
}
Completely dynamic messages
In this case you have a collection of unrelated key-values and process them individually.
Parse into a map[string]interface{}. The downside, of course, is that you have to cast each value and check its type dynamically. Caveat: map[string]interface{} will convert all numbers to floats, even integers, so you have cast them to float64.
You can also use map[string]json.RawMessage, if you do not want to parse values, only keys (json.RawMessage is a []byte, and is preserved as is when unmarshaled).
"Envelope" message with dynamic payload
For example:
{
"type": "foo",
"payload": {
"key1": "value1"
}
}
{
"type": "bar",
"payload": {
"key2": "value2",
"key3": [1, 2]
}
}
Use a struct with json.RawMessage.
type Message struct {
Type string
Payload json.RawMessage
}
type Foo struct {
Key1 string
}
type Bar struct {
Key2 string
Key3 []int
}
Parse the envelope (payload will be preserved), then dispatch on type, and parse payload into a sub-struct.
var m Message
_ = json.Unmarshal(data, &m)
switch m.Type {
case "foo":
var payload Foo
_ = json.Unmarshal(m.Payload, &payload)
// do stuff
case "bar":
var payload Bar
_ = json.Unmarshal(m.Payload, &payload)
// do stuff
}

Unmarshal nested JSON structure

http://play.golang.org/p/f6ilWnWTjm
I am trying to decode the following string but only getting null values.
How do I decode nested JSON structure in Go?
I want to convert the following to map data structure.
package main
import (
"encoding/json"
"fmt"
)
func main() {
jStr := `
{
"AAA": {
"assdfdff": ["asdf"],
"fdsfa": ["1231", "123"]
}
}
`
type Container struct {
Key string `json:"AAA"`
}
var cont Container
json.Unmarshal([]byte(jStr), &cont)
fmt.Println(cont)
}
Use nested structs in Go to match the nested structure in JSON.
Here's one example of how to handle your example JSON:
package main
import (
"encoding/json"
"fmt"
"log"
)
func main() {
jStr := `
{
"AAA": {
"assdfdff": ["asdf"],
"fdsfa": ["1231", "123"]
}
}
`
type Inner struct {
Key2 []string `json:"assdfdff"`
Key3 []string `json:"fdsfa"`
}
type Container struct {
Key Inner `json:"AAA"`
}
var cont Container
if err := json.Unmarshal([]byte(jStr), &cont); err != nil {
log.Fatal(err)
}
fmt.Printf("%+v\n", cont)
}
playground link
You can also use an anonymous type for the inner struct:
type Container struct {
Key struct {
Key2 []string `json:"assdfdff"`
Key3 []string `json:"fdsfa"`
} `json:"AAA"`
}
playground link
or both the outer and inner structs:
var cont struct {
Key struct {
Key2 []string `json:"assdfdff"`
Key3 []string `json:"fdsfa"`
} `json:"AAA"`
}
playground link
If you don't know the field names in the inner structure, then use a map:
type Container struct {
Key map[string][]string `json:"AAA"`
}
http://play.golang.org/p/gwugHlCPLK
There are more options. Hopefully this gets you on the right track.
First of all: Don't ignore errors returned by a function or method unless you have a very good reason to do so.
If you make the following change to the code:
err := json.Unmarshal([]byte(jStr), &cont)
if err != nil {
fmt.Println(err)
}
You will see the error message telling you why the value is empty:
json: cannot unmarshal object into Go value of type string
Simply put: Key cannot be of type string, so you have to use a different type. You have several option on how to decode it depending on the characteristics of the Key value:
If the structure is static, use another struct to match this structure.
If the structure is dynamic, use interface{} (or map[string]interface{} if it is always of type JSON object)
If the value is not to be accessed, only to be used in later JSON encoding, or if the decoding is to be delayed, use json.RawMessage

How to parse an inner field in a nested JSON object

I have a JSON object similar to this one:
{
"name": "Cain",
"parents": {
"mother" : "Eve",
"father" : "Adam"
}
}
Now I want to parse "name" and "mother" into this struct:
struct {
Name String
Mother String `json:"???"`
}
I want to specify the JSON field name with the json:... struct tag, however I don't know what to use as tag, because it is not the top object I am interested in. I found nothing about this in the encoding/json package docs nor in the popular blog post JSON and Go. I also tested mother, parents/mother and parents.mother.
You could use structs so long as your incoming data isn't too dynamic.
http://play.golang.org/p/bUZ8l6WgvL
package main
import (
"fmt"
"encoding/json"
)
type User struct {
Name string
Parents struct {
Mother string
Father string
}
}
func main() {
encoded := `{
"name": "Cain",
"parents": {
"mother": "Eve",
"father": "Adam"
}
}`
// Decode the json object
u := &User{}
err := json.Unmarshal([]byte(encoded), &u)
if err != nil {
panic(err)
}
// Print out mother and father
fmt.Printf("Mother: %s\n", u.Parents.Mother)
fmt.Printf("Father: %s\n", u.Parents.Father)
}
Unfortunately, unlike encoding/xml, the json package doesn't provide a way to access nested values. You'll want to either create a separate Parents struct or assign the type to be map[string]string. For example:
type Person struct {
Name string
Parents map[string]string
}
You could then provide a getter for mother as so:
func (p *Person) Mother() string {
return p.Parents["mother"]
}
This may or may not play into your current codebase and if refactoring the Mother field to a method call is not on the menu, then you may want to create a separate method for decoding and conforming to your current struct.
Here's some code I baked up real quick in the Go Playground
http://play.golang.org/p/PiWwpUbBqt
package main
import (
"fmt"
"encoding/json"
)
func main() {
encoded := `{
"name": "Cain",
"parents": {
"mother": "Eve"
"father": "Adam"
}
}`
// Decode the json object
var j map[string]interface{}
err := json.Unmarshal([]byte(encoded), &j)
if err != nil {
panic(err)
}
// pull out the parents object
parents := j["parents"].(map[string]interface{})
// Print out mother and father
fmt.Printf("Mother: %s\n", parents["mother"].(string))
fmt.Printf("Father: %s\n", parents["father"].(string))
}
There might be a better way. I'm looking forward to seeing the other answers. :-)
More recently, gjson supports selection of nested JSON properties.
name := gjson.Get(json, "name")
mother := gjson.Get(json, "parents.mother")
How about using an intermediary struct as the one suggested above for parsing, and then putting the relevant values in your "real" struct?
import (
"fmt"
"encoding/json"
)
type MyObject struct{
Name string
Mother string
}
type MyParseObj struct{
Name string
Parents struct {
Mother string
Father string
}
}
func main() {
encoded := `{
"name": "Cain",
"parents": {
"mother": "Eve",
"father": "Adam"
}
}`
pj := &MyParseObj{}
if err := json.Unmarshal([]byte(encoded), pj); err != nil {
return
}
final := &MyObject{Name: pj.Name, Mother: pj.Parents.Mother}
fmt.Println(final)
}