How to represent Golang struct with variable field names [duplicate] - json

This question already has answers here:
How to Unmarshal jSON with dynamic key which can't be captured as a `json` in struct: GOlang [duplicate]
(1 answer)
How to parse/deserialize dynamic JSON
(4 answers)
Closed 8 months ago.
If this has been answered somewhere else let me know but I couldn't find anything.
Basically, let's say we have the following JSON. string-id-001 can be an arbitrary string. We want to unmarshal it into a struct, and be able to access the unique id's.
{"list":{"string-id-001":{"id":"blah","name":"cool"},"string-id-002":{"id":"yas","name":"rad"}}}
Golang as far as I can tell would require something like below which doesn't work if the keyhere value is constantly changing. Eg if it's an ID
type Foo struct {
List struct {
StringID001 struct {
ID string `json:"id"`
Name string `json:"name"`
} `json:"string-id-001"`
StringID002 struct {
ID string `json:"id"`
Name string `json:"name"`
} `json:"string-id-002"`
} `json:"list"`
}
I've seen a similar issue in another project (which I solved with interfaces rather than structs), and I'm wondering if there's a nicer solution. Am I missing something obvious?

type payLoad struct {
ID string `json:"id"`
Name string `json:"name"`
}
type Foo struct {
List map[string]payLoad `json:"list"`
}

Related

Representing a list of things of different type in JSON and Golang [duplicate]

This question already has answers here:
Is it possible to partially decode and update JSON? (go)
(2 answers)
How to parse a complicated JSON with Go unmarshal?
(3 answers)
golang | unmarshalling arbitrary data
(2 answers)
How to parse JSON in golang without unmarshaling twice
(3 answers)
Decoding generic JSON objects to one of many formats
(1 answer)
Closed 9 months ago.
I'm trying to represent some data in JSON where there is a list of things where each thing has some common features (ex name) and another field who's value can either be a string or an integer. For example:
{
"items": [
{
"name": "thing1",
"type": "string",
"value": "foo"
},
{
"name": "thing2",
"type": "int",
"value": 42
}
]
}
That JSON looks reasonable to me, but trying to create a data structure to deserialize (unmarshal) it into in Golang is proving difficult. I think I could do it in Java with class polymorphism, but in Go I feel trapped. I've tried many things but haven't got it. Ultimately, it comes down to lack of struct type polymorphism.
In Go, I can have a slice (list) of interfaces, but I need actual structs of different types as far as I can tell.
Any suggestions on how to represent this in Golang, and be able to unmarshal into?
Or alternatively, should I structure the JSON itself differently?
Thanks!
You can create a structure like this
type items struct {
name string
type_1 string
value interface{}
}
Interface can hold any data type, also as type is reserved keyword i have used type_1
You can do it in Go 1.18 like this:
type Data struct {
Items []struct {
Name string `json:"name"`
Type string `json:"type"`
Value any `json:"value"`
} `json:"items"`
}
func main() {
data := Data{}
// it's your json bytes
bytesData := []byte()
if err := json.Unmarshal(byteData, &data); err != nil {
log.Fatal(err)
}
}
// use data here
P.S. if you are using older versions use interface{} instead of any.
This data structure properly represents your JSON:
type Data struct {
Items []struct {
Name string `json:"name"`
Type string `json:"type"`
Value interface{} `json:"value"`
} `json:"items"`
}
Then, you can use json.Unmarshal.
If you use Go 1.18, you can use any alias of interface{}.
In addition, in Go you don't even need a type field. You can use Type assertions to determine the value type.

Golang Json Marshall encoding synthax [duplicate]

This question already has answers here:
Lowercase JSON key names with JSON Marshal in Go
(4 answers)
Closed 7 years ago.
i would know if json.Marshal Put Uppercase a the first letter of each name fields ? I need to encode some data with just a lowercase at each field name first letter.
just:
{
"name":"thomas"
}
instead of:
{
"Name":"thomas"
}
Thanks !
You have to add an annotation to the Name field.
Supposing your struct is:
type User struct {
Name string
}
You have to change it to:
type User struct {
Name string `json:"name"`
}
The json marshaller will replace Name with name

Struct for JSON objects in GO [duplicate]

This question already has an answer here:
Strange type definition syntax in Golang (name, then type, then string literal)
(1 answer)
Closed 7 years ago.
I'm learning GO and when defining structs for working with JSON like below.
type List struct {
ID string `datastore:"-"`
Name string
}
I see that there is this text in between ` sign. I have not been able to find an explanation what that signifies.
Things seem to work even without those.
They are struct tags used in Marshal'ing Go struct into JSON. In JSON, unlike Go, fields are in lowercase strings. Therefore, most use cases would be
type List struct {
ID string `json:"id"`
Name string `json:"name"`
}
In JSON
{
"id": "some id",
"name": "some name"
}
See post here

Golang Struct Won't Marshal to JSON [duplicate]

This question already has answers here:
My structures are not marshalling into json [duplicate]
(3 answers)
Closed 7 years ago.
I'm trying to marshal a struct in Go to JSON but it won't marshal and I can't understand why.
My struct definitions
type PodsCondensed struct {
pods []PodCondensed `json:"pods"`
}
func (p *PodsCondensed) AddPod(pod PodCondensed) {
p.pods = append(p.pods, pod)
}
type PodCondensed struct {
name string `json:"name"`
colors []string `json:"colors"`
}
Creating and marshaling a test struct
fake_pods := PodsCondensed{}
fake_pod := PodCondensed {
name: "tier2",
colors: []string{"blue", "green"},
}
fake_pods.AddPod(fake_pod)
fmt.Println(fake_pods.pods)
jPods, _ := json.Marshal(fake_pods)
fmt.Println(string(jPods))
Output
[{tier2 [blue green]}]
{}
I'm not sure what the issue is here, I export json data for all my structs, the data is being stored correctly and is available to print. It just wont marshal which is odd because everything contained in the struct can be marshaled to JSON on its own.
This is a common mistake: you did not export values in the PodsCondensed and PodCondensed structures, so the json package was not able to use it. Use a capital letter in the variable name to do so:
type PodsCondensed struct {
Pods []PodCondensed `json:"pods"`
}
type PodCondensed struct {
Name string `json:"name"`
Colors []string `json:"colors"`
}
Working example: http://play.golang.org/p/Lg3cTO7DVk
Documentation: http://golang.org/pkg/encoding/json/#Marshal

Golang and JSON with array of struct [duplicate]

This question already has answers here:
My structures are not marshalling into json [duplicate]
(3 answers)
Closed 7 months ago.
I would like to create a JSON of a GatewayInfo where the type are defined like this:
type SpanInfo struct {
imsi string
network string
network_status string
signal_quality int
slot int
state string
}
type GatewayInfo []SpanInfo
The gateway information is created with:
var gatewayInfo = make(GatewayInfo, nb_spans)
To create the JSON, I use the json.Marshal function:
gatewayInfo := getGatewayInfo(spans)
log.Printf("Polling content: %s\n", gatewayInfo)
jsonInfo, _ := json.Marshal(gatewayInfo)
log.Printf("jsonInfo: %s\n", jsonInfo)
Unfortunately the result is not what I was expecting:
2015/02/09 13:48:26 Polling content: [{652020105829193 20801 Registered (Roaming) %!s(int=17) %!s(int=2) } {652020105829194 20801 Registered (Roaming) %!s(int=16) %!s(int=3) } {652020105829192 20801 Registered (Roaming) %!s(int=19) %!s(int=1) } {652020105829197 20801 Registered (Roaming) %!s(int=19) %!s(int=4) }]
2015/02/09 13:48:26 jsonInfo: [{},{},{},{}]
As we can see, the GatewayInfo instance has the SpanInfo, but in the JSON I have empty SpanInfo.
Your struct fields must be exported (field is exported if it begins with a capital letter) or they won't be encoded:
Struct values encode as JSON objects. Each exported struct field
becomes a member of the object
To get the JSON representation as probably expected change the code to this:
type SpanInfo struct {
IMSI string `json:"imsi"`
Network string `json:"network"`
NetworkStatus string `json:"network_status"`
SignalQuality int `json:"signal_quality"`
Slot int `json:slot"`
State string `json:"state"`
}
type GatewayInfo []SpanInfo
The json package can only serialize exported fields of your struct. Change your struct to start all fields with an uppercase letter so they can be included in the output:
type SpanInfo struct {
Imsi string
Network string
Network_status string
Signal_quality int
Slot int
State string
}
Read the documentation of json.Marshal() for details and more information.
This is not a new answer. It is just consolidation of comments on the
accepted answer.
From ORIGINAL Query
type SpanInfo struct {
imsi string
network string
network_status string
signal_quality int
slot int
state string
}
From Answer and comments - Please note that the first char of each field in struct is now in UPPER case along with json representation added to each field
type SpanInfo struct {
IMSI string `json:"imsi"`
Network string `json:"network"`
NetworkStatus string `json:"network_status"`
SignalQuality int `json:"signal_quality"`
Slot int `json:slot"`
State string `json:"state"`
}