Access nested map

hello folks,
I have a json file and I am accessing the same and trying to convert to struct using json.Unmarshal while doing so I have nested key value pairs in the json. How do I access nested map specifically the “tables” the non nested is straight forward. Please help

My json looks like
cat http1.json
{
“deviceGroup”: “none”,
“fullPath”: “/Common/top”,
“inheritedDevicegroup”: “true”,
“inheritedTrafficGroup”: “true”,
“tables”: [
{
“name”: “basic__snatpool_members”
},
{
“name”: “net__snatpool_members”
},
{
“name”: “optimizations__hosts”
},
{
“columnNames”: [
“name”
],

}

========function here

func dataToIapp(name string, d *schema.ResourceData) bigip.Iapp {
var p bigip.Iapp

var obj map[string]interface{}

jsonblob := []byte(d.Get("jsonfile").(string))
err := json.Unmarshal(jsonblob, &obj)
if err != nil {
	fmt.Println("error", err)
}

log.Printf("value of +++++++++++++++++++++++++++++all objects %+v\n p ", obj)
p.Name = obj[“name”].(string)
p.Partition = obj[“partition”].(string)
p.Devicegroup = obj[“deviceGroup”].(string)
p.InheritedDevicegroup = obj[“inheritedDevicegroup”].(string)
p.Tables = obj[“tables”].(string)

when I compile I get this error
go build

bigip/resource_bigip_sys_iapp.go:319:11: cannot use obj[“tables”].(string) (type string) as type []bigip.Tablesrecord in assignment

my struct is as below

package bigip

import (
“encoding/json”
//“log”
)

// LIC contains device license for BIG-IP system.

type Iapps struct {
Iapps []Iapp json:"items"
}

type Iapp struct {
Name string
Partition string
Description string
Devicegroup string
ExecuteAction string
InheritedDevicegroup string
StrictUpdates string
Template string
TemplateModified string
TemplatePrerequisiteErrors string
TrafficGroup string
InheritedTrafficGroup string
Lists []Listsrecord
Metadata []Metadatarecord
Tables []Tablesrecord
Variables []Variablesrecord
Jsonfile string
}
type iappDTO struct {
Name string json:"name,omitempty"
Partition string json:"partition,omitempty"
Description string json:"description,omitempty"
Devicegroup string json:"deviceGroup,omitempty"
ExecuteAction string json:"executeAction,omitempty"
InheritedDevicegroup string json:"inheritedDevicegroup,omitempty"
InheritedTrafficGroup string json:"inheritedTrafficGroup,omitempty"
StrictUpdates string json:"strictUpdates,omitempty"
Template string json:"template,omitempty"
TemplateModified string json:"templateModified,omitempty"
TemplatePrerequisiteErrors string json:"templatePrerequisiteErrors,omitempty"
TrafficGroup string json:"trafficGroup,omitempty"
Jsonfile string json:"apiAnonymous,omitempty"

Lists                      struct {
	Items []Listsrecord `json:"items,omitempty"`
} `json:"listsReference,omitempty"`
Metadata struct {
	Items []Metadatarecord `json:"items,omitempty"`
} `json:"metadataReference,omitempty"`
Tables struct {
	Items []Tablesrecord `json:"items,omitempty"`
} `json:"tablesReference,omitempty"`
Variables struct {
	Items []Variablesrecord `json:"items,omitempty"`
} `json:"variablesReference,omitempty"`

}

type Listsrecord struct {
Encrypted string json:"encrypted"
Value string json:"value"
}

type Metadatarecord struct {
Persist string json:"persist"
Value string json:"value"
}

type Tablesrecord struct {
ColumnNames string json:"columnNames"
Name string json:"name"
EncryptedColumns string json:"encryptedColumns"
Rows string json:"rows"
}

type Variablesrecord struct {
Encrypted string json:"encrypted"
Name string json:"name"
Value string json:"value"
}

I’m new to Go, so I don’t know if this is a good practice. I would make 3 structs, 2 for your two tables, and 1 that contains your two tables.

type metaData struct{
deviceGroup string json:“deviceGroup”

table1 Table1 json:"table1"
table2 Table2 json:“table2”
}

type table1 struct{
key string json:“key”

}

type table2 struct{
key string json:“key”

}

Hi @scshitole, For me, You can parse the JSON into an interface{} instead of a struct. In your JSON it contains a variety of structure situations. here is my code example.

var your_json = []byte(`{"name":"Miracle","project":[{"another":"assignment"}]}`)

func main() {

var obj interface{} // Parse json into an interface{}

err := json.Unmarshal(your_json,&obj)
if err != nil {
	fmt.Println(err)
}

m := obj.(map[string]interface{}) // Important: to access property
fmt.Println(m["name"])
fmt.Println(m["project"])

}

// Output:
// Miracle
// [map[another:assignment]]

Take note, You we’ll get an error “invalid character ‘:’ after array element” if your project contains like this “project: [“another”:“assignment”]”, you should add your data into a map “project: [{“another”:“assignment”}]”.

@adriel

Thanks Its giving me assertion type message when I compile.

go build

bigip/resource_bigip_sys_iapp.go:316:10: cannot use m[“name”] (type interface {}) as type string in assignment: need type assertion
bigip/resource_bigip_sys_iapp.go:317:14: cannot use m[“partition”] (type interface {}) as type string in assignment: need type assertion
bigip/resource_bigip_sys_iapp.go:320:11: cannot use m[“tables”] (type interface {}) as type []bigip.Tablesrecord in assignment: need type assertion

func dataToIapp(name string, d *schema.ResourceData) bigip.Iapp {
var p bigip.Iapp

var obj interface{}

jsonblob := []byte(d.Get("jsonfile").(string))
err := json.Unmarshal(jsonblob, &obj)
if err != nil {
	fmt.Println("error", err)
}

log.Printf("value of +++++++++++++++++++++++++++++all objects %+v\n p ", obj)
m := obj.(map[string]interface{}) // Important: to access property
p.Name = m[“name”]
p.Partition = m[“partition”]
//p.Devicegroup = obj[“deviceGroup”].(string)
//p.InheritedDevicegroup = obj[“inheritedDevicegroup”].(string)
p.Tables = m[“tables”]

@adriel

I updated with assertion
m := obj.(map[string]interface{}) // Important: to access property
p.Name = m[“name”].(string)
p.Partition = m[“partition”].(string)
//p.Devicegroup = obj[“deviceGroup”].(string)
//p.InheritedDevicegroup = obj[“inheritedDevicegroup”].(string)
p.Tables = m[“tables”].(string)

go build
bigip/resource_bigip_sys_iapp.go:320:11: cannot use m[“tables”].(string) (type string) as type []bigip.Tablesrecord in assignment

The error has gone for “name” and “partition” however but I cannot use m[“tables”].(string)

@adriel
I want to populate the struct Iapp with the JSON so I am trying to read the key values and assign it to stuct fields like p.Tables, p. Partition, p.Tables and so on … where p is bigip.Iapp and Iapp is as below

type Iapp struct {
Name string
Partition string
Description string
Devicegroup string
ExecuteAction string
InheritedDevicegroup string
StrictUpdates string
Template string
TemplateModified string
TemplatePrerequisiteErrors string
TrafficGroup string
InheritedTrafficGroup string
Lists []Listsrecord
Metadata []Metadatarecord
Tables []Tablesrecord
Variables []Variablesrecord
Jsonfile string
}
type iappDTO struct {
Name string json:"name,omitempty"
Partition string json:"partition,omitempty"
Description string json:"description,omitempty"
Devicegroup string json:"deviceGroup,omitempty"
ExecuteAction string json:"executeAction,omitempty"
InheritedDevicegroup string json:"inheritedDevicegroup,omitempty"
InheritedTrafficGroup string json:"inheritedTrafficGroup,omitempty"
StrictUpdates string json:"strictUpdates,omitempty"
Template string json:"template,omitempty"
TemplateModified string json:"templateModified,omitempty"
TemplatePrerequisiteErrors string json:"templatePrerequisiteErrors,omitempty"
TrafficGroup string json:"trafficGroup,omitempty"
Jsonfile string json:"apiAnonymous,omitempty"

Lists                      struct {
	Items []Listsrecord `json:"items,omitempty"`
} `json:"listsReference,omitempty"`
Metadata struct {
	Items []Metadatarecord `json:"items,omitempty"`
} `json:"metadataReference,omitempty"`
Tables struct {
	Items []Tablesrecord `json:"items,omitempty"`
} `json:"tablesReference,omitempty"`
Variables struct {
	Items []Variablesrecord `json:"items,omitempty"`
} `json:"variablesReference,omitempty"`

}

type Listsrecord struct {
Encrypted string json:"encrypted"
Value string json:"value"
}

type Metadatarecord struct {
Persist string json:"persist"
Value string json:"value"
}

type Tablesrecord struct {
ColumnNames string json:"columnNames"
Name string json:"name"
EncryptedColumns string json:"encryptedColumns"
Rows string json:"rows"
}

type Variablesrecord struct {
Encrypted string json:"encrypted"
Name string json:"name"
Value string json:"value"
}

func (p *Iapp) MarshalJSON() ([]byte, error) {
return json.Marshal(iappDTO{
Name: p.Name,
Partition: p.Partition,
Description: p.Description,
Devicegroup: p.Devicegroup,
ExecuteAction: p.ExecuteAction,
InheritedDevicegroup: p.InheritedDevicegroup,
StrictUpdates: p.StrictUpdates,
Template: p.Template,
TemplateModified: p.TemplateModified,
TemplatePrerequisiteErrors: p.TemplatePrerequisiteErrors,
TrafficGroup: p.TrafficGroup,
InheritedTrafficGroup: p.InheritedTrafficGroup,
Lists: struct {
Items []Listsrecord json:"items,omitempty"
}{Items: p.Lists},
Metadata: struct {
Items []Metadatarecord json:"items,omitempty"
}{Items: p.Metadata},
Tables: struct {
Items []Tablesrecord json:"items,omitempty"
}{Items: p.Tables},
Variables: struct {
Items []Variablesrecord json:"items,omitempty"
}{Items: p.Variables},
})
}

func (p *Iapp) UnmarshalJSON(b []byte) error {
var dto iappDTO
err := json.Unmarshal(b, &dto)
if err != nil {
return err
}

p.Name = dto.Name
p.Partition = dto.Partition
p.Description = dto.Description
p.Devicegroup = dto.Devicegroup
p.ExecuteAction = dto.ExecuteAction
p.InheritedDevicegroup = dto.InheritedDevicegroup
p.StrictUpdates = dto.StrictUpdates
p.Template = dto.Template
p.TemplateModified = dto.TemplateModified
p.TemplatePrerequisiteErrors = dto.TemplatePrerequisiteErrors
p.TrafficGroup = dto.TrafficGroup
p.InheritedTrafficGroup = dto.InheritedTrafficGroup
p.Lists = dto.Lists.Items
p.Metadata = dto.Metadata.Items
p.Tables = dto.Tables.Items
p.Variables = dto.Variables.Items

return nil

}

When the JSON unmarshaled, the values in JSON are converted into the following Go types: string, bool, float64 or map[string]interface{}, nil etc…, so I suggest to do a function that recursively walking the parsed JSON.

func printjson(your_json interface{}) {
	switch json_type := your_json.(type) {
		case string:
			//... You can print the value here, or return it as value.
		case float64:
			//...
		case []interface{}:
			//...
		case map[string]interface{}:
			for index, json_value := range json_type {
				printjson(json_value)
			} 
		default:
			fmt.Println("Unknown type.")
	}
}

With this function, you can do another assertion to get the value, but you need to add return type in printjson. Hope this will help to you.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.