parsing nested JSON with go - go

I am trying to parse a nested json on GO ,
the json looks like this:
{
"id" : 12345656,
"date" : "2018-05-02-18-16-17",
"lists" : [
{
"empoyee_id": "12343",
"name": "User1"
},
{
"contractor_id" : "12343",
"name": "User1"
},
{
"contractor_id" : "12343",
"name": "User1"
}
]
}
My struct
type Result struct {
id int64 `json:"id"`
Date string `json:"date"`
Lists []string `json:"lists"`
}
I am trying to access it using the following:
var result Result
json.Unmarshal(contents, &result)
How can I change the above to access to the employee_id or the contractor_id fields ?

You need to use another type to store the nested data rather than a slice of strings like so:
package main
import (
"fmt"
"encoding/json"
)
var contents string = `{
"id" : 12345656,
"date" : "2018-05-02-18-16-17",
"lists" : [
{
"empoyee_id": "12343",
"name": "User1"
},
{
"contractor_id" : "12343",
"name": "User1"
},
{
"contractor_id" : "12343",
"name": "User1"
}
]
}`
type Result struct {
ID int64 `json:"id"`
Date string `json:"date"`
Lists []Contractor `json:"lists"`
}
type Contractor struct {
ContractorID string `json:"contractor_id"`
EmployeeID string `json:"employee_id"`
Name string `json:"name"`
}
func main() {
var result Result
err := json.Unmarshal([]byte(contents), &result)
if err != nil {
panic(err)
}
fmt.Println(result)
}
Executable:
https://play.golang.org/p/7dYArgz1V8y
If you just want a single ID field on the nested object then you will need to do a custom unmarshal function on the result to work out which ID is present.

Related

How to access a subfield present in an Interface?

I want to fetch url value i.e. hahaha from this interface (without using indexing) using Golang.
I want url from this interface using GOLANG
{
"data" : [
{
"key" : "xyz",
"val" : "ftghj"
},
{
"key" : "url",
"val" : "hahaha"
}
]
}
I tried this method, but here i have to use indexing
resbodyMap := make(map[string]interface{})
json.Unmarshal([]byte(data), &resbodyMap) // (here my data was in the byte format)`
data := resbodyMap["extendedData"]
Url := extData.([]interface{})[1]
mp := Url.(map[string]interface{})
url := mp["val"]
I want url from this interface using GOLANG
are you want like this?
package main
import (
"encoding/json"
"fmt"
)
var data = `{
"data" : [
{
"key" : "xyz",
"val" : "ftghj"
},
{
"key" : "url",
"val" : "hahaha"
}
]
}`
type KeyValue struct {
Val *string `json:"val"`
}
type Data struct {
Data []*KeyValue `json:"data"`
}
func main() {
var val string
json.Unmarshal([]byte(data), &Data{[]*KeyValue{nil, {&val}}})
fmt.Println(val)
}
However, it is not useful in actual use.

How to parse JSON-RPC table with different type

I want get informations in JSON-RPC file with this structure :
{
"id": "foo1",
"error": null,
"result": [
{
"key": [
"hello 1",
1,
"world 1"
],
"val": {
"type": "static"
}
},
{
"key": [
"hello 2",
1,
"world 2"
],
"val": {
"type": "static"
}
}
]
}
This is my parsing function, Key is string table (can't accept int type) :
type JsonRpcRsp struct {
Id string `json:"id"`
Error *string `json:"error"`
Result json.RawMessage `json:"result"`
}
type JsonRpcEntry_Val struct {
Type string `json:"type"`
}
type JsonRpcEntry struct {
Key [3]string `json:"key"`
Val JsonRpcEntry_Val `json:"val"`
}
jsonResult := JsonRpcRsp{}
json.Unmarshal(data, &jsonResult)
entries := []JsonRpcEntry{}
for _, val := range jsonResult {
json.Unmarshal(val.Result, &entries)
}
How to parse "key" table ?... problem is there are different types
key table structure is :
[ <string>, <int>, <string>]
To unmarshal arrays of different types in Go you'll need to use interfaces and consequently type assertions if you need access to the types.
This will work for you:
type Result struct {
Key [3]interface{} `json:"key"`
Val struct {
Type string `json:"type"`
} `json:"val"`
}
msg := JsonRpcRsp{}
json.Unmarshal(data, &msg)
var result []Result
json.Unmarshal(msg.Result, &result)
for _, v := range result {
key1 := v.Key[0].(string)
key2 := v.Key[1].(float64)
key3 := v.Key[2].(string)
fmt.Println(key1, key2, key3)
}
After asserting the three interfaces to their types, you can then work with them further, depending on your use case.

How to get the number of items from a structure sub field using reflect in go

I have some issues when getting the number of items from a sub field in a slice struct through reflect package.
This is how I'm trying to get the number of items from Items
func main() {
type Items struct {
Name string `json:"name"`
Present bool `json:"present"`
}
type someStuff struct {
Fields string `json:"fields"`
Items []Items `json:"items"`
}
type Stuff struct {
Stuff []someStuff `json:"stuff"`
}
some_stuff := `{
"stuff": [
{
"fields": "example",
"items": [
{ "name": "book01", "present": true },
{ "name": "book02", "present": true },
{ "name": "book03", "present": true }
]
}
]
}`
var variable Stuff
err := json.Unmarshal([]byte(some_stuff), &variable)
if err != nil {
panic(err)
}
//I want to get the number of items in my case 3
NumItems := reflect.ValueOf(variable.Stuff.Items)
}
This is the error:
variable.Items undefined (type []Stuff has no field or method Items)
I'm unsure if I can retrieve the number of items like that.
I have already fixed the issue.
In order to get the number of sub fields we can make use of Len() from reflect.ValueOf.
The code now is getting the number of Items:
package main
import (
"encoding/json"
"fmt"
"reflect"
)
func main() {
type Items struct {
Name string `json:"name"`
Present bool `json:"present"`
}
type someStuff struct {
Fields string `json:"fields"`
Items []Items `json:"items"`
}
type Stuff struct {
Stuff []someStuff `json:"stuff"`
}
some_stuff := `{
"stuff": [
{
"fields": "example",
"items": [
{ "name": "book01", "present": true },
{ "name": "book02", "present": true },
{ "name": "book03", "present": true }
]
}
]
}`
var variable Stuff
err := json.Unmarshal([]byte(some_stuff), &variable)
if err != nil {
panic(err)
}
//I want to get the number of items in my case 3
t := reflect.ValueOf(variable.Stuff[0].Items)
fmt.Println(t.Len())
}
Output: 3

Golang Facebook response to struct

Hi there I'm new in GO and I'm trying to convert a json from the facebook api to struct.
The problem is that the keys of the object are dinamic:
{
"100555213756790": {
"id": "100555213756790",
"about": "Noodle Bar & Restaurant",
"metadata": {
"fields": [
{
"name": "id",
"description": "asdasdasdasd",
"type": "numeric string"
},
//...
,
"101285033290986": {
"id": "101285033290986",
"about": "Smart City Expo World Congress",
"metadata": {
"fields": [
{
"name": "id",
"description": "fgddgdfgdg",
"type": "numeric string"
},
what I have achieved so far is extract the objects by id and turn them into a map:
for _, id := range ids {
fbPages, ok := results[string(id)].(map[string]interface{})
if ok {
for k, v := range fbPages {
fmt.Println(k)
fmt.Println(v)
}
}
}
//json to Page struct?
type Page struct {
ID string `json:"id"`
About string `json:"about"`
}
type Metadata struct {
Fields []Field `json:"fields"`
Type string `json:"type"`
Connections map[string]string `json:"connections"`
}
type Field struct {
Name string `json:"name"`
Description string `json:"description"`
Type *string `json:"type,omitempty"`
}
My question is:
how can I convert that map to struct? or is there any easy way to do what I'm trying to do?
Thank you
Converting map to struct:
import "github.com/mitchellh/mapstructure"
mapstructure.Decode(myMap, &myStruct)
example
But I would do this:
type Page struct {
ID string `json:"id"`
About string `json:"about"`
//other fields and nested structs like your metadata struct
}
type fbPages map[string]Page

golang mgo modelling issue

I have this model data which I use to save data to the database
type Nos struct {
UnitCode string `json:"unitCode" bson:"unitCode"`
Version string `json:"version" bson:"version"`
Reviews struct {
ReviewCommentsHistory []reviewCommentsHistory `json:"reviewCommentsHistory" bson:"reviewCommentsHistory"`
}
ID bson.ObjectId `bson:"_id"`
CreatedAt time.Time `bson:"created_at"`
UpdatedAt time.Time `bson:"updated_at"`
}
type reviewCommentsHistory struct {
ReviewHistoryDate time.Time `json:"reviewHistoryDate" bson:"reviewHistoryDate,omitempty"`
}
My mongodb data is as follows
{
"_id" : ObjectId("5a992d5975885e236c8dc723"),
"unitCode" : "G&J/N3601",
"version" : "3",
"Reviews" : {
"reviewCommentsHistory" : [
{
"reviewHistoryDate" : ISODate("2018-04-28T18:30:00.000Z")
}
]
}
}
Using golang package mgo I have written the following piece of code to get the document
func (nosDal NosDal) FindNos(unitCode string, version string) ([]model.Nos, error) {
var result []model.Nos
var err error
col := repository.DB.C("nos")
err = col.Find(bson.M{"unitCode": strings.ToUpper(unitCode), "version": version}).All(&result)
fmt.Println(result[0])
return result, err
}
My response returns the value of null for Reviews.reviewCommentsHistory. Is there an issue with my model? Any pointers would be useful on how to check if the response is mapping to my model
This is my output
{
"unitCode": "G&J/N3601",
"version": "3",
"Reviews": {
"reviewCommentsHistory": null
},
"ID": "5a992d5975885e236c8dc723",
"CreatedAt": "2018-03-02T16:24:17.19+05:30",
"UpdatedAt": "2018-03-05T18:04:28.478+05:30"
}
The problem is that for the Nos.Reviews field you did not specify any bson tag, which means the default mapping will be applied, which means the field name will be used with lowercase letter: "reviews". But your MongoDB contains the document with a capital letter: "Reviews", so the mapping will fail (unmarshaling will not match the MongoDB "Reviews" to the Nos.Reviews field).
Specify the missing tag:
Reviews struct {
ReviewCommentsHistory []reviewCommentsHistory `json:"reviewCommentsHistory" bson:"reviewCommentsHistory"`
} `json:"Reviews" bson:"Reviews"`
And it will work.

Resources