Decode 2nd level response body to struct - go

I have 2 structs:
type List struct {
ListID string `json:"listid"`
Name string `json:"name"`
Users []User `json:"users"`
}
type User struct {
Email string `json:"email"`
Name string `json:"name"`
}
I am calling an endpoint and successfully getting a response which has the structure below:
{
"Results":[
{"Email": "user1#domain.com", "Name": "test1" "State": "Active",…},
{"Email": "user2#domain.com", "Name": "test2" "State": "Active",…},
{"Email": "user3#domain.com", "Name": "test3", "State": "Active",…}
],
"SomeOtherStuff": "email"
}
I am trying to decode the JSON response to my struct like this:
err = json.NewDecoder(response.Body).Decode(&list.Users)
But there is no "Results" attribute in my struct to map to. How can I map only the Results key of the response to my array of User structs ?

To get your data there are at least two options:
Decode into map[string]interface{}
m := create(map[string]interface{})
err = json.NewDecoder(response.Body).Decode(&m)
Then use the m["results"] key to get at your users.
Or you could Decode into a container struct then assign list.Users = container.Results.
type Container struct {
Results []User `json:"Results"`
SomeOtherStuff string `json:"SomeOtherStuff"`
}
To get an idea of structs for arbitrary json look at json2go.

Related

How can I query and return only id array by GORM?

I'm now having a problem with getting an id of array feeds from database (Postgres) with Gorm.
How can I query and return id array feeds? I don't know how to get only id from struct without loop
feeds := []models.Feed{}
feedID := []string{}
db.Select("id").Where("user_id = ?", "admin1").Find(&feeds)
for _, feed := range feeds {
feedID = append(feedID, feed.ID)
}
utils.PrintStruct(feeds)
This is feed model file:
type Feed struct {
Model
Status string `json:"status"`
PublishAt *time.Time `json:"publishAt"`
UserID string `json:"userID,omitempty"`
}
This is model base data model using for data entity:
type Model struct {
ID string `json:"id" gorm:"primary_key"`
}
Result:
[
{
"id": "d95d4be5-b53c-4c70-aa09",
"status": "",
"publishAt": null,
"userID":""
},
{
"id": "84b2d46f-a24d-4854-b44d",
"status": "",
"publishAt": null,
"userID":""
}
]
But I want like this:
["d95d4be5-b53c-4c70-aa09","84b2d46f-a24d-4854-b44d"]
You can use pluck
var ids []string
db.Model(&Feed{}).Where("user_id = ?", "admin1").Pluck("id", &ids)

Unmarshalling nested JSON objects in GO

I combined some properties common to all objects into a struct.
type Document struct {
ID string `json:"_id,omitempty"`
UpdatedAt time.Time `json:"updatedat"`
CreatedAt time.Time `json:"createdat"`
}
I also have an address struct, which is not a document.
type Address struct {
AddressLine string `json:"addressline,omitempty"`
City string `json:"city,omitempty"`
Country string `json:"country,omitempty"`
CityCode int `json:"citycode,omitempty"`
}
My customer struct is a document. It also has an address property.
type Customer struct {
Document `json:"document"`
Address Address `json:"address"`
Name string `json:"name,omitempty"`
Email string `json:"email,omitempty"`
Valid bool `json:"valid,omitempty"`
}
The JSON object from MongoDB is as follows;
[
{
"_id": "6186b4556971a9dbae117333",
"address": {
"addressline": "Foo Address",
"city": "Foo City",
"citycode": 0,
"country": "Foo Country"
},
"document": {
"createdat": "0001-01-01T03:00:00+03:00",
"updatedat": "0001-01-01T03:00:00+03:00"
},
"email": "foo#mail.com",
"name": "Foo Fooster",
"valid": false
}
]
I am using the following code to unmarshal this.
var customerEntity Entities.Customer
json.Unmarshal(customerEntityBytes, &customerEntity)
But all I can get is the following line. Most fields are empty.
{{ 0001-01-01 00:00:00 +0000 UTC 0001-01-01 00:00:00 +0000 UTC} { 0} false}
As I thought this was due to the mixed nested structure, I created another customer struct for testing purposes;
import "time"
type AutoGenerated []struct {
ID string `json:"_id"`
Address struct {
Addressline string `json:"addressline"`
City string `json:"city"`
Citycode int `json:"citycode"`
Country string `json:"country"`
} `json:"address"`
Document struct {
Createdat time.Time `json:"createdat"`
Updatedat time.Time `json:"updatedat"`
} `json:"document"`
Email string `json:"email"`
Name string `json:"name"`
Valid bool `json:"valid"`
}
All of a sudden the whole problem was fixed and I was able to access it with all fields filled.
In summary, I cannot unmarshal the Custumer struct I want to use. Do I need to override the unmarshall method for this? I've also reviewed the override examples but the codes are very subjective. A change I will make in base classes will cause me to change the unmarshall method. What is the clean way to this?
Always check errors.
err = json.Unmarshal(customerEntityBytes, &customerEntity)
if err != nil {
// json: cannot unmarshal array into Go value of type Entities.Customer
}
and the reason is, as #mkopriva pointed out - your JSON is an array - and you are unmarshaling to a single struct. To fix:
var customerEntity []Entities.Customer // use slice to capture JSON array
err = json.Unmarshal(customerEntityBytes, &customerEntity)
if err != nil { /* ... */ }
You can certainly use your custom types, but you are losing the _id tag by nesting it in your Document struct. To fix, promote it to Customer:
type Document struct {
//ID string `json:"_id,omitempty"`
UpdatedAt time.Time `json:"updatedat"`
CreatedAt time.Time `json:"createdat"`
}
type Customer struct {
ID string `json:"_id,omitempty"`
// ...
}
Working example: https://play.golang.org/p/EMcC0d1xOLf

How to get/extract values of a JSON

I'm trying to get values/index/key of a JSON but no success. I found some answers and tutorials but I couldn't get them working for me.
I have the following JSON:
{
"id": "3479",
"product": "Camera",
"price": "",
"creation": 04032020,
"products": [
{
"camera": "Nikon",
"available": true,
"freeshipping": false,
"price": "1,813",
"color": "black"
},
{
"camera": "Sony",
"available": true,
"freeshipping": true,
"price": "931",
"color": "black"
}
],
"category": "eletronics",
"type": "camera"
}
I have tried several examples but none worked for this type of Json.
The error I'm getting:
panic: interface conversion: interface {} is nil, not
map[string]interface {}
I believe it's because of "products[]" I tried map[string]interface{} and []interface{} it compiles but gives me that error afterwards.
Could you give me an example on how I can extract these values?
The code I'm using:
//gets the json
product,_:=conn.GetProductData(shop.Info.Id)
// assing a variable
productInformation:=<-product
//prints the json
fmt.Printf(productInformation)
//try to get json values
type Product struct {
Id string
Product string
}
var product Product
json.Unmarshal([]byte(productInformation), &product)
fmt.Printf("Id: %s, Product: %s", product.Id, product.Product)
This code does not panic but it doesn't print all results either so I tried
this one below (which was supposed to give me all results) but it panics
var result map[string]interface{}
json.Unmarshal([]byte(productInformation), &result)
// The object stored in the "birds" key is also stored as
// a map[string]interface{} type, and its type is asserted from
// the interface{} type
products := result["products"].(map[string]interface{})
for key, value := range products {
// Each value is an interface{} type, that is type asserted as a string
fmt.Println(key, value.(string))
}
You need to add json tag to specify the field name in json as it is in lowercase
type Product struct {
Id string `json:"id"`
Product string `json:"product"`
}
And in the second case according to json it is a slice not a map so you need to cast it to []interface{}
var result map[string]interface{}
json.Unmarshal([]byte(productInformation), &result)
// The object stored in the "birds" key is also stored as
// a map[string]interface{} type, and its type is asserted from
// the interface{} type
products := result["products"].([]interface{})
for key, value := range products {
// Each value is an interface{} type, that is type asserted as a string
fmt.Println(key, value)
}

How do you convert specific array values in a JSON response to be just the first value in the array?

(Note, Dgraph isn't required for this problem; it's just the tool I am using where I am encountering the problem)
Let's say you have some structs
type AccountSettings struct {
Uid string `json:"uid"`
DType string `json:"dgraph.type"`
Name string `json:"name"`
Username string `json:"username"`
}
type Settings struct {
Uid string `json:"uid"`
DType string `json:"dgraph.type"`
Account AccountSettings `json:"account"`
}
type Tag struct {
Uid string `json:"uid"`
DType string `json:"dgraph.type"`
Label Label `json:"label"`
}
type User struct {
Uid string `json:"uid"`
DType string `json:"dgraph.type"`
Settings Settings `json:"settings"`
Tags []Tag `json:"tags"`
}
and you create a user and add it to your Dgraph database
user = User{
DType: "User",
Settings: Settings{
DType: "Settings",
Account: SettingsAccount{
DType: "SettingsAccount",
Name: "Billy Bob"
Username: "billyboy123"
},
Tags: []Tag{{
DType: "Tag",
Label: "admin"
}, {
DType: "Tag",
Label: "user"
}}
},
}
And then you query your Dgraph database like (assuming you have the uid of the user node)
{
user(func: uid("0x1234")) {
uid
settings {
account {
name
username
}
}
tags {
label
}
}
}
the response will come back as
{
"data": {
"user": [
{
"uid": "0x1234"
"settings": [
{
"account": [
{
"name": "Billy Bob",
"username": "billyboy123"
}
]
}
]
"tags": [
{
label: "admin"
},
{
label: "user"
},
]
}
]
}
}
So the problem is that the JSON response of Dgraph will return fields of struct types as arrays (presumably because there could potentially be multiple nodes pointing to a single other node), but since it's an array, you can't immediately marshal it with the User struct (because User.Settings is of type Settings, not []Settings).
What would you do in order to marshal the Dgraph JSON response with the User struct (or any other kind of struct)?
It's important to note that the settings array in the JSON response should just be the first element in that array, but the tags array should still remain an array because that's what's specified in the User struct.
You can do this with a custom Unmarshal as described here:
http://choly.ca/post/go-json-marshalling/
You use an alias by embedding the original User in an anonymous type that has a slice of Settings inside it that you Umarshal into like so:
func (u *User) UnmarshalJSON(data []byte) error {
type Alias User
aux := &struct {
Settings []*Settings `json:"settings"`
*Alias
}{
Alias: (*Alias)(u),
}
if err := json.Unmarshal(data, &aux); err != nil {
return err
}
u.Settings = aux.Settings[0]
return nil
}
A full working example is here (you need the same trick for the AccountSettings):
https://play.golang.org/p/FQWakX8B7OF

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

Resources