Unmarshalling a JSON object with JSON array into a struct - json

I want to unmarshal an array of json object into a struct. Each json object has a json array for one of the properties. If the property is defined as a string, works. If it's defined as an array of byte or string, I get an error.
I have tried a number of approaches but keep getting an error.
panic: ERROR: json: cannot unmarshal string into Go struct field
.productlist of type []string
Source file:
{
"orgs": [
{
"orgname": "Test Organization 26",
"orgs_id": 26,
"contactdate": "2019-12-12",
"sincedate": "2019-12-12",
"estusers": null,
"estvehicles": null,
"paidusers": null,
"paythreshold": null,
"productlist": "[\"SDCC\",\"JOB_CARDS\",\"ALLOCATIONS\"]",
"roles": "[\"DISPATCH\",\"DRIVERS\",\"MECHANICS\"]"
}
]
}
Go Struct:
type OrgsJSONData struct {
Orgs []struct {
Orgname string `json:"orgname"`
OrgsID int `json:"orgs_id"`
Contactdate string `json:"contactdate"`
Sincedate string `json:"sincedate"`
Estusers interface{} `json:"estusers"`
Estvehicles interface{} `json:"estvehicles"`
Paidusers interface{} `json:"paidusers"`
Paythreshold interface{} `json:"paythreshold"`
Productlist []string `json:"productlist"`
Roles string `json:"roles"`
} `json:"orgs"`
}
Code:
var orgsJSONData OrgsJSONData
tmp := []byte(strings.Join(JsonData, ""))
err := json.Unmarshal(tmp, &orgsJSONData)
if err != nil {
panic("ERROR: " + err.Error())
}
If the productlist property is a string, the unmarshal works. If it is any other slice or array, I get the error "panic: ERROR: json: cannot unmarshal string into Go struct field .productlist of type []string" What am I doing wrong. P.S. Very new to Golang (Week 2 and learning)

The productlist field in the JSON input is a string, not an array:
"productlist": "[\"SDCC\",\"JOB_CARDS\",\"ALLOCATIONS\"]"
Note that the contents of it are quoted, and enclosed quotes are escaped. This is a string, not an array.
If it was an array, it would have been:
"productlist": ["SDCC","JOB_CARDS","ALLOCATIONS"]

Related

How to set optional json in nest struct

I tried to set an optional json config in nest struct, when i need this json it will appear, otherwise it will not exist.
type Test struct {
Data NestTest `json:"data"`
}
type NestTest struct {
NestData1 string `json:"data1"`
NestData2 string `json:"data2,omitempty"`
}
test := Test{
Data: NestTest{
NestData1: "something",
},
}
b, err := json.Marshal(test)
fmt.Sprintf("the test struct json string is: %s", string(b))
output:
{"data":{"data1":"something","data2":""}}
expect:
{"data":{"data1":"something"}}
All fields are optional when unmarshalling (you won't get an error if a struct field doesn't have an associated value in the JSON). When marshaling, you can use omitempty to not output a field if it contains its type's zero value:
https://pkg.go.dev/encoding/json#Marshal
var Test struct {
Data string `json:"data,omitempty" validate:"option"`
}

Retrieve element from nested JSON string

This is the Go code that I have:
func main(){
s := string(`{"Id": "ABC123",
"Name": "Hello",
"RelatedItems":[
{"RId":"TEST123","RName":"TEST1","RChildren":"Ch1"},
{"RId":"TEST234","RName":"TEST2","RChildren":"Ch2"}]
}`)
var result map[string]interface{}
json.Unmarshal([]byte(s), &result)
fmt.Println("Id:", result["Id"])
Rlist := result["RelatedItems"].([]map[string]interface{})
for key, pist := range pist {
fmt.Println("Key: ", key)
fmt.Println("RID:", pist["RId"])
}
}
The struct is down below
type Model struct {
Id string `json:"Id"`
Name string `json:"ModelName"`
RelatedItems []RelatedItems `json:"RelatedItems"`
}
type RelatedItems struct {
RId string `json:"PCId"`
RName string `json:"PCName"`
RChildren string `json:"string"`
}
How would I get an output that would let me choose a particular field from the above?
eg:
Output
Id: ABC123
key:0
RID:TEST123
key:1
RID:TEST234
I am seeing this error
panic: interface conversion: interface {} is nil, not []map[string]interface {}
Based on the posted content,
I'm clear that you are facing issues retrieving data from the nested JSON string.
I've taken your piece of code and tried to compile and reproduce the issue.
After observing, I have a few suggestions based on the way the code has been written.
When the datatype present in the s is known to be similar to the type Model, the result could have been declared as type Model.
That results in var result Model instead of map[string]interface{}.
When the data that's gonna be decoded from the interface{} is not known, the usage of switch would come into rescue without crashing the code.
Something similar to:
switch dataType := result["RelatedItems"].(type){
case interface{}:
// Handle interface{}
case []map[string]interface{}:
// Handle []map[string]interface{}
default:
fmt.Println("Unexpected-Datatype", dataType)
// Handle Accordingly
When we try to Unmarshal, we make sure to look into the json tags that are provided for the fields of a structure. If the data encoded is not having the tags we provided, the data will not be decoded accordingly.
Hence, the result of decoding the data from s into result would result in {ABC123 [{ } { }]} as the tags of the fields Name, RId, RName, RChildren are given as ModelName, PCId, PCName, string respectively.
By the above suggestions and refining the tags given, the piece of code would be as following which would definitely retrieve data from nested JSON structures.
s := string(`{"Id": "ABC123",
"Name": "Hello",
"RelatedItems":[
{"RId":"TEST123","RName":"TEST1","RChildren":"Ch1"},
{"RId":"TEST234","RName":"TEST2","RChildren":"Ch2"}]
}`)
var result Model
json.Unmarshal([]byte(s), &result)
fmt.Println(result)
type Model struct {
Id string `json:"Id"`
Name string `json:"Name"`
RelatedItems []RelatedItems `json:"RelatedItems"`
}
type RelatedItems struct {
RId string `json:"RId"`
RName string `json:"RName"`
RChildren string `json:"RChildren"`
}
This results in the output: {ABC123 Hello [{TEST123 TEST1 Ch1} {TEST234 TEST2 Ch2}]}
Why would you unmarshal to a map anyway and go through type checks?
type Model struct {
Id string `json:"Id"`
Name string `json:"ModelName"`
RelatedItems []RelatedItems `json:"RelatedItems"`
}
type RelatedItems struct {
RId string `json:"PCId"`
RName string `json:"PCName"`
RChildren string `json:"string"`
}
s := `{"Id": "ABC123",
"Name": "Hello",
"RelatedItems":[
{"RId":"TEST123","RName":"TEST1","RChildren":"Ch1"},
{"RId":"TEST234","RName":"TEST2","RChildren":"Ch2"}]
}`
var result Model
if err := json.Unmarshal([]byte(s), &result); err != nil {
log.Fatal(err.Error())
}
fmt.Println("Id: ", result.Id)
for index, ri := range result.RelatedItems {
fmt.Printf("Key: %d\n", index)
fmt.Printf("RID: %s\n", ri.RId)
}

The type of property not the same when reading from input stream

The code used for testing for listing users.
req := httptest.NewRequest("GET", "/v1/users", nil)
resp := httptest.NewRecorder()
u.app.ServeHTTP(resp, req)
if resp.Code != http.StatusOK {
t.Fatalf("getting users: expected status code %v, got %v", http.StatusOK, resp.Code)
}
var list []map[string]interface{}
if err := json.NewDecoder(resp.Body).Decode(&list); err != nil {
t.Fatalf("decoding users: %s", err)
}
want := []map[string]interface{}{
{
"id": "a2b0639f-2cc6-44b8-b97b-15d69dbb511e",
"name": "dcc",
"role_id": float64(101),
"date_created": "2019-01-01T00:00:01Z",
"date_updated": "2019-01-01T00:00:01Z",
},
}
The role_id is a int type in model.
type User struct {
ID string `db:"user_id" json:"id"`
UserName string `db:"user_name" json:"user_name"`
RoleID int `db:"role_id" json:"role_id"`
DateCreated time.Time `db:"date_created" json:"date_created"`
DateUpdated time.Time `db:"date_updated" json:"date_updated"`
}
Why it is changed to float64 when inputing to the stream?
User.RoleID is an integer, and it will be encoded into a JSON Number. And
because you unmarshal into a value of type map[string]interface{} (the value type is interface), float64 type is chosen when unmarshaling into an interface value.
Quoting from json.Unmarshal():
To unmarshal JSON into an interface value, Unmarshal stores one of these in the interface value:
bool, for JSON booleans
float64, for JSON numbers
string, for JSON strings
[]interface{}, for JSON arrays
map[string]interface{}, for JSON objects
nil for JSON null
If you know the response holds a User object, unmarshal into a value of type User.

cannot unmarshal array into Go struct when decoding array

I'm trying to properly decode JSON String to an object.
I defined the following structs:
type AjaxModelsList struct {
Id float64 `json:"Id"`
Name string `json:"Name"`
CarId float64 `json:"CarId"`
EngName string `json:"EngName"`
}
type AjaxModelsData struct {
ModelList []AjaxModelsList `json:"ModelList"`
}
type AjaxModels struct {
Status bool `json:"status"`
Data map[string]AjaxModelsData `json:"data"`
}
the defined object is
{
"status": true,
"data": {
"ModelList": [{
"Id": 1,
"Name": "foo",
"CarId": 1,
"EngName": "bar"
}]
}
}
and I unmarshall using the following code:
c :=AjaxModels{}
if err := json.Unmarshal(body_byte,&c); err != nil {
log.Fatalf("an error occured: %v",err)
}
and I get the following output:
an error occured: json: cannot unmarshal array into Go struct field AjaxModels.data of type main.AjaxModelsData
since I used []AjaxModelsList it's a slice so I shouldn't be getting this error. I probably missed something, but what ?
In the json the data structure is object[key]array, while in Go Data is map[key]struct.slice. Change Data to be map[key]slice instead.
E.g.
type AjaxModels struct {
Status bool `json:"status"`
Data map[string][]AjaxModelsList `json:"data"`
}
https://play.golang.org/p/Sh_vKVL-D--

Golang json decoding fails on Array

I have an object like:
a = [{
"name": "rdj",
"place": "meh",
"meh" : ["bow", "blah"]
}]
I defined a struct like:
type first struct {
A []one
}
type one struct {
Place string `json: "place"`
Name string `json: "name"`
}
when I use the same in code like:
func main() {
res, _ := http.Get("http://127.0.0.1:8080/sample/")
defer res.Body.Close()
var some first
rd := json.NewDecoder(res.Body)
err := rd.Decode(&some)
errorme(err)
fmt.Printf("%+v\n", some)
}
I get the below error:
panic: json: cannot unmarshal array into Go value of type main.first
My understanding is:
type first defines the array and within that array is data structure defined in type one.
The JSON is an array of objects. Use these types:
type one struct { // Use struct for JSON object
Place string `json: "place"`
Name string `json: "name"`
}
...
var some []one // Use slice for JSON array
rd := json.NewDecoder(res.Body)
err := rd.Decode(&some)
The the types in the question match this JSON structure:
{"A": [{
"name": "rdj",
"place": "meh",
"meh" : ["bow", "blah"]
}]}
#rickydj,
If you need to have "first" as a separate type:
type first []one
If you do not care about having "first" as a separate type, just cut down to
var some []one
as #Mellow Marmot suggested above.