Why is json values empty - go

Can you see why json values dont get saved:
Update: And if you would like to explain why this is downgraded as "Off topic"?
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
)
type UsedInContext struct {
UsedIn string `json:"usedin"`
ContextName string `json:"contextname"`
}
type ContextData struct {
usedInContext []UsedInContext `json:"usedincontext"`
}
func saveData() {
var jsonBlob = []byte(`{
"usedincontext":
[
{"usedin":"local", "contextname":"desktop"}
]
}`)
usedInContext := UsedInContext{}
err := json.Unmarshal(jsonBlob, &usedInContext)
if err != nil {
}
usedInContextJson, _ := json.Marshal(usedInContext)
err = ioutil.WriteFile("data.json", usedInContextJson, 0644)
fmt.Printf("%+v", usedInContext)
}
I get the following:
{"usedin":"","contextname":""}

You unmarshal your document to the type UsedInContext, while it matches the schema for ContextData:
type ContextData struct {
UsedInContext []UsedInContext `json:"usedincontext"` // exported
}
var data ContextData
json.Unmarshal(jsonBlob, &data)
fmt.Printf("%+v", data)

Related

How to extract data from map[string]interface{}?

I am sending the data to the API like following:
{"after": {"amount": 811,"id":123,"status":"Hi"}, "key": [70]}
and i am getting following while printing :
map[after:map[amount:811 id:123 status:Hi ] key:[70]]
Is there any way to print individual field like this??
amount::800
id:123
status:Hi
The code:
package main
import (
"encoding/json"
"fmt"
"io"
"io/ioutil"
"log"
"net/http"
"strings"
)
var (
PORT = ":8080"
)
func main() {
fmt.Println("In Main")
http.HandleFunc("/", changedData)
http.ListenAndServe(PORT, nil)
}
type Data struct {
Id int64 `json:"id"`
Amount float64 `json:"amount"`
Status string `json:"status"`
}
type mark map[string]interface{}
func changedData(w http.ResponseWriter, r *http.Request) {
fmt.Println("Coming From API")
reqBody, _ := ioutil.ReadAll(r.Body)
fmt.Println("Data coming from API ", string(reqBody))
digit := json.NewDecoder(strings.NewReader(string(reqBody)))
for digit.More() {
var result mark
err := digit.Decode(&result)
if err != nil {
if err != io.EOF {
log.Fatal(err)
}
break
}
fmt.Println("final_data ", result)
}
}
Decode to a Go type that matches the structure of the JSON document. You declared a type for the "after" field. Wrap that type with a struct to match the document.
func changedData(w http.ResponseWriter, r *http.Request) {
var v struct{ After Data }
err := json.NewDecoder(r.Body).Decode(&v)
if err != nil {
http.Error(w, "bad request", 400)
return
}
fmt.Printf("final_data: %#v", v.After)
}
Playground example.
I think you can define a struct type if you know the JSON file format or if the JSON format is predefined. As far as I know that mostly using interface{} is a way when you don't know the JSON format or there is no predefined format of the JSON. If you define a struct type  and use it while unmarshaling the JSON to struct, you can access the variables by typing like data.Id or data.Status.
Here's an example code:
package main
import (
"encoding/json"
"fmt"
)
type Data struct {
AfterData After `json:"after"`
Key []int `json:"key"`
}
type After struct {
Id int64 `json:"id"`
Amount float64 `json:"amount"`
Status string `json:"status"`
}
func main() {
j := []byte(`{"after": {"amount": 811,"id":123,"status":"Hi"}, "key": [70]}`)
var data *Data
err := json.Unmarshal(j, &data)
if err != nil {
fmt.Println(err.Error())
return
}
fmt.Println(data.AfterData)
fmt.Println(data.AfterData.Id)
fmt.Println(data.AfterData.Amount)
fmt.Println(data.AfterData.Status)
}
Output will be
{123 811 Hi}
123
811
Hi
Go Playground

Reading and Unmarshalling API results in Golang

In the below program I'm extracting some data from an API.
It outputs a rather complex data.
When I ioutil.ReadAll(resp.Body), the result is of type []uint8.
If I try to read the results, its just a random array of integers.
However, I'm able to read it if I convert it to string using string(diskinfo)
But I want to use this in a Struct and having trouble unmarshalling.
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"net/url"
"reflect"
)
type ApiResults struct {
results []struct {
statement_id int `json.statement_id`
series []struct {
name string `json.name`
tags struct {
host string `json.host`
}
columns []string `json.columns`
values []interface{} `json.values`
}
}
}
func main() {
my_url := "my_url"
my_qry := fmt.Sprintf("my_query")
resp, err := http.Get(my_url + url.QueryEscape(my_qry))
if err != nil {
fmt.Printf("ERROR: %v\n", err)
} else {
fmt.Println(reflect.TypeOf(resp))
diskinfo, _ := ioutil.ReadAll(resp.Body)
fmt.Println(reflect.TypeOf((diskinfo)))
fmt.Println(diskinfo)
fmt.Println(string(diskinfo))
diskinfo_string := string(diskinfo)
data := ApiResults{}
json.Unmarshal([]byte(diskinfo_string), &data)
//fmt.Printf("Values = %v\n", data.results.series.values)
//fmt.Printf("Server = %v\n", data.results.series.tags.host)
}
}
If I view the data as a string, I get this (formatted):
{"results":[
{"statement_id":0,
"series":[
{"name":"disk",
"tags":{"host":"myServer1"},
"columns":["time","disk_size"],
"values":[["2021-07-07T07:53:32.291490387Z",1044]]},
{"name":"disk",
"tags":{"host":"myServer2"},
"columns":["time","disk_size"],
"values":[["2021-07-07T07:53:32.291490387Z",1046]]}
]}
]}
I think my Apireturn struct is also structured incorrectly because the API results have info for multiple hosts.
But first, I doubt if the data has to be sent in a different format to the struct. Once I do this, I can probably try to figure out how to read from the Struct next.
The ioutil.ReadAll already provides you the data in the type byte[]. Therefore you can just call json.Unmarshal passing it as a parameter.
import (
"encoding/json"
"io/ioutil"
"net/http"
)
func toStruct(res *http.Response) (*ApiResults, error) {
body, err := ioutil.ReadAll(res.Body)
if err != nil {
return nil, err
}
defer res.Body.Close()
data := ApiResults{}
if err := json.Unmarshal(body, &data); err != nil {
return nil, err
}
return data, nil
}
There also seems to be an issue with your struct. The correct way to use struct tags is as follows. Plus, fields need to be exported for the json tag (used by json.Umarshal) to work – starting with uppercase will do it.
type ApiResults struct {
Results []struct {
StatementId int `json:"statement_id"`
Series []struct {
Name string `json:"name"`
Tags struct {
Host string `json:"host"`
} `json:"tags"`
Columns []string `json:"columns"`
Values []interface{} `json:"values"`
} `json:"series"`
} `json:"results"`
}

MongoDB distinct query and $in with Go

I'm having trouble with the distinct query in MongoDB.
I can write it in Mongo shell, it works but I don't know how to implement it in Go code.
Here is my Mongo shell code
db.getCollection('company_role_function').distinct("rolecode", {rolecode : {
$in: ['DHBK_ROLE_01','DHBK_ROLE_03' ] },productid:'IOT_Platform'
})
And here is my Go code
1.profile.go
type CompanyRoleFunction struct {
Rolecode string `json:"rolecode"`
Productid string `json:"productid"`
Functioncode string `json:"functioncode"`
Comid string `json:"comid"`
}
repository.go
package repository
import "bitbucket.org/cloud-platform/vnpt-sso-usermgnt/model"
type IProfileRepository interface {
FindRoleByUserProduct(string) (*model.CompanyRoleFunction, error)
}
mongo_driver.go
package repository
import (
"bitbucket.org/cloud-platform/vnpt-sso-usermgnt/model"
"go.mongodb.org/mongo-driver/bson"
"gopkg.in/mgo.v2"
)
type ProfileRepositoryMongo struct {
db *mgo.Database
collection string
}
func NewProfileRepositoryMongo(db *mgo.Database, collection string) *ProfileRepositoryMongo {
return &ProfileRepositoryMongo{
db: db,
collection: collection,
}
}
//I HAVE TROUBLE HERE
func (r *ProfileRepositoryMongo) FindRoleByUserProduct(rolecode arr[]string) (*model.CompanyRoleFunction, error) {
var companyRoleFunction model.CompanyRoleFunction
//I HAVE TROUBLE HERE
err := r.db.C(r.collection).Find(bson.M{"username": username}).One(&companyRoleFunction)
//I HAVE TROUBLE HERE
if err != nil {
return nil, err
}
return &companyRoleFunction, nil
}
Try the below code for distinct in mgo
package main
import (
"context"
"fmt"
"time"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"gopkg.in/mgo.v2"
)
type Result struct {
Rolecode string `json:"rolecode"`
Productid string `json:"productid"`
Functioncode string `json:"functioncode"`
Comid string `json:"comid"`
}
type Results []Result
func main() {
//delete1("GV_BMVT")
//update("GV_BMVT")
check()
}
func check() {
session, err := mgo.Dial("mongodb://casuser:Mellon#222.255.102.145:27017/users")
if err != nil {
panic(err)
}
c := session.DB("users").C("company_role_function")
results := []string{}
roleArray := []string{"DHBK_ROLE_01,", "DHBK_ROLE_03"}
err = c.Find(bson.M{"rolecode": bson.M{"$in": roleArray}, "productid": "IOT_Platform"}).Distinct("rolecode", &results)
if err != nil {
panic(err)
}
fmt.Println(results)
}

Unmarshalling array into struct

I'm trying to figure out how I can (using gin) create a struct from an api call
"icon": [
"https://api.figo.me/assets/images/accounts/postbank.png",
{
"48x48": "https://api.figo.me/assets/images/accounts/postbank_48.png",
"60x60": "https://api.figo.me/assets/images/accounts/postbank_60.png",
"72x72": "https://api.figo.me/assets/images/accounts/postbank_72.png",
"84x84": "https://api.figo.me/assets/images/accounts/postbank_84.png",
"96x96": "https://api.figo.me/assets/images/accounts/postbank_96.png",
"120x120": "https://api.figo.me/assets/images/accounts/postbank_120.png",
"144x144": "https://api.figo.me/assets/images/accounts/postbank_144.png",
"192x192": "https://api.figo.me/assets/images/accounts/postbank_192.png",
"256x256": "https://api.figo.me/assets/images/accounts/postbank_256.png"
}
],
into
type CatalogBank struct {
Advice string `json:"advice"`
BankCode string `json:"bank_code"`
BankName string `json:"bank_name"`
BIC string `json:"bic"`
Credentials []struct {
Label string `json:"label"`
Masked bool `json:"masked"`
} `json:"credentials"`
Icon []struct {
} `json:"icon"`
Language []byte `json:"language"`
}
The icon part is just an extract from, but I always get an unmarshall error for this part. How would I have to definde the 'Icon' part in the struct?
This would work
package main
type CatalogBank struct {
Icon []interface{} `json:"icon"`
}
This is a little tricky in Golang because of the non-strict type in the JSON. If that is definitely the format you are going to receive the data in, you should unmarshal to an Interface{} and then parse the interface into a struct that you can use in your Golang
Direct Unmarshalling cannot be done, as the type of each field is not known
type Icon struct{
ImageLink string
ImageLink48 string
// ...
}
type CatalogBank struct {
Advice string `json:"advice"`
IconRaw []interface{} `json:"icon"`
Icon []Icon
//...
}
func UnmarshalIcon(c &CatalogBank, i interface{}):
// first convert it to the top level list
newIcon := Icon{}
listOfIcons := i.([]interface{})
for _, i := range listOfIcons:
switch iT := i.(type) {
case string:
newIcon.ImageLink = iT
case map[string]interface{}:
for smallIconsKey, smallIconLink := range iT {
if smallIconsKey == "48x48"{
newIcon.ImageLink48 = smallIconLink.(string)
}
// and so on
}
var c CatalogBank{}
_ := json.Unmarshal([]byte(your_json), &c)
for _, i := range c.IconRaw:
UnmarshalIcon(&c, i)
Caveat Emptor: I haven't checked above implementation but it should be something like this
You can not use []struct {} for icon, change it to []interface{} instead, or if you want operate on type safe type look at the second solution with cusom unmarshaler
Solution 1
package main
import (
"encoding/json"
"fmt"
"log"
)
type CatalogBank struct {
Advice string `json:"advice"`
BankCode string `json:"bank_code"`
BankName string `json:"bank_name"`
BIC string `json:"bic"`
Credentials []struct {
Label string `json:"label"`
Masked bool `json:"masked"`
} `json:"credentials"`
Icon []interface{} `json:"icon"`
Language []byte `json:"language"`
}
func main() {
data := `
{
"Advice":"abc",
"icon": [
"https://api.figo.me/assets/images/accounts/postbank.png",
{
"48x48": "https://api.figo.me/assets/images/accounts/postbank_48.png",
"60x60": "https://api.figo.me/assets/images/accounts/postbank_60.png",
"72x72": "https://api.figo.me/assets/images/accounts/postbank_72.png",
"84x84": "https://api.figo.me/assets/images/accounts/postbank_84.png",
"96x96": "https://api.figo.me/assets/images/accounts/postbank_96.png",
"120x120": "https://api.figo.me/assets/images/accounts/postbank_120.png",
"144x144": "https://api.figo.me/assets/images/accounts/postbank_144.png",
"192x192": "https://api.figo.me/assets/images/accounts/postbank_192.png",
"256x256": "https://api.figo.me/assets/images/accounts/postbank_256.png"
}
]
}
`
bank := &CatalogBank{}
err := json.Unmarshal([]byte(data), bank)
if err != nil {
log.Fatal(err)
}
for _, icon := range bank.Icon {
fmt.Printf(" %v\n ", icon)
}
}
Solution 2:
package main
import (
"encoding/json"
"fmt"
"log"
)
type Icons struct {
URL string
BySize map[string]string
}
type CatalogBank struct {
Advice string `json:"advice"`
BankCode string `json:"bank_code"`
BankName string `json:"bank_name"`
BIC string `json:"bic"`
Credentials []struct {
Label string `json:"label"`
Masked bool `json:"masked"`
} `json:"credentials"`
Icon *Icons `json:"-,"`
Language []byte `json:"language"`
}
func (p *CatalogBank) Unmarshal(data []byte) error {
type Transient struct {
*CatalogBank
Icon []interface{} `json:"icon"`
}
var transient = &Transient{CatalogBank:p}
err := json.Unmarshal([]byte(data), transient)
if err != nil {
return err
}
p.Icon = &Icons{
BySize: make(map[string]string),
}
if len(transient.Icon) > 0 {
if url, ok := transient.Icon[0].(string); ok {
p.Icon.URL = url
}
if aMap, ok := transient.Icon[1].(map[string]interface{}); ok {
for k, v := range aMap {
p.Icon.BySize[k] = v.(string)
}
}
}
return nil
}
func main() {
data := `
{
"Advice":"abc",
"icon": [
"https://api.figo.me/assets/images/accounts/postbank.png",
{
"48x48": "https://api.figo.me/assets/images/accounts/postbank_48.png",
"60x60": "https://api.figo.me/assets/images/accounts/postbank_60.png",
"72x72": "https://api.figo.me/assets/images/accounts/postbank_72.png",
"84x84": "https://api.figo.me/assets/images/accounts/postbank_84.png",
"96x96": "https://api.figo.me/assets/images/accounts/postbank_96.png",
"120x120": "https://api.figo.me/assets/images/accounts/postbank_120.png",
"144x144": "https://api.figo.me/assets/images/accounts/postbank_144.png",
"192x192": "https://api.figo.me/assets/images/accounts/postbank_192.png",
"256x256": "https://api.figo.me/assets/images/accounts/postbank_256.png"
}
]
}
`
bank := &CatalogBank{}
err := bank.Unmarshal([]byte(data))
if err != nil {
log.Fatal(err)
}
fmt.Printf("advice: %v\n", bank.Advice)
fmt.Printf("icon: %v\n", bank.Icon.URL)
for size, icon := range bank.Icon.BySize {
fmt.Printf("%v => %v\n ",size, icon)
}
}
You can define your icon like this:
package main
import (
"fmt"
"encoding/json"
)
var testIcon = []byte(`{"icon":[
"https://api.figo.me/assets/images/accounts/postbank.png",
{
"48x48":"https://api.figo.me/assets/images/accounts/postbank_48.png"
}]
}`)
func main() {
icon := make(map[string][]interface{})
err := json.Unmarshal(testIcon, &icon)
if err != nil {
panic(err)
}
fmt.Println(icon)
// map[icon:[https://api.figo.me/assets/images/accounts/postbank.png map[48x48:https://api.figo.me/assets/images/accounts/postbank_48.png]]]
}

Golang - unmarshal extra XML attributes

Is there a way to unmarshal XML tags with dynamic attributes (I don't know which attributes I'll get every time).
Maybe it's not supported yet. See Issue 3633: encoding/xml: support for collecting all attributes
Something like :
package main
import (
"encoding/xml"
"fmt"
)
func main() {
var v struct {
Attributes []xml.Attr `xml:",any"`
}
data := `<TAG ATTR1="VALUE1" ATTR2="VALUE2" />`
err := xml.Unmarshal([]byte(data), &v)
if err != nil {
panic(err)
}
fmt.Println(v)
}
As of late 2017, this is supported by using:
var v struct {
Attributes []xml.Attr `xml:",any,attr"`
}
Please see https://github.com/golang/go/issues/3633
You need to implement your own XMLUnmarshaler
package main
import (
"encoding/xml"
"fmt"
)
type CustomTag struct {
Name string
Attributes []xml.Attr
}
func (c *CustomTag) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
c.Name = start.Name.Local
c.Attributes = start.Attr
return d.Skip()
}
func main() {
v := &CustomTag{}
data := []byte(`<tag ATTR1="VALUE1" ATTR2="VALUE2" />`)
err := xml.Unmarshal(data, &v)
if err != nil {
panic(err)
}
fmt.Printf("%+v\n", v)
}
outputs
&{Name:tag Attributes:[{Name:{Space: Local:ATTR1} Value:VALUE1} {Name:{Space: Local:ATTR2} Value:VALUE2}]}
http://play.golang.org/p/9ZrpIT32o_

Resources