Capitals in struct fields - json

I'm using this library to access CouchDB (cloudant to be specific) "github.com/mikebell-org/go-couchdb" and I've noticed a problem.
When I go to add a file to the database and pass in a struct, only the fields of the struct which started with a capital letter get added.
For example
type Person struct {
name string
Age int
}
func main() {
db, _ := couchdb.Database(host, database, username, password)
joe := Person{
name: "mike",
Age: 190,
}
m, _ := db.PostDocument(joe)
}
In this case, only the "age" field got updated and inserted into my database.
I've noticed this problem in another case also - when I'm doing something like this :
type Sample struct {
Name string
age int
}
joe := Sample{
Name: "xx",
age: 23,
}
byt, _ := json.Marshal(joe)
post_data := strings.NewReader(string(byt))
fmt.Println(post_data)
in this case, only Name would be printed out :
output : &{{"Name":"xx"} 0 -1}
Why is this? and If I would like to have a field with a lowercase and be inside the database, is that possible?

This is because only fields starting with a capital letter are exported, or in other words visible outside the curent package (and in the json package in this case).
Here is the part of the specifications refering to this: http://golang.org/ref/spec#Exported_identifiers
Still, you can unmarshall json fields that do no start with a capital letters using what is called "tags". With the json package, this is the syntax to use:
type Sample struct {
Name string `json:"name"`
Age int `json:"age"`
}
Refer to the documentation for more information about this.

json package only stringfiy fields start with capital letter.
see http://golang.org/pkg/encoding/json/
Struct values encode as JSON objects. Each exported struct field becomes a member of the object, using the field name as the object key, unless the field is omitted for one of the reasons given below.
You need define the struct like this:
type Sample struct{
Name string `json:"name"`
Age int `json:"age"`
}

json.Marshal method struct-in field-i only accepts fields that start with a capital letter
The json package only accesses the exported fields of struct types (those that begin with an uppercase letter). Therefore only the exported fields of a struct will be present in the JSON output.
type Sample struct {
Name string
Age int
}

Related

Accessing Data in Nested []struct

I'm working on unmarshaling some nested json data that I have already written a struct for. I've used a tool that will generate a struct based off json data, but am a bit confused how to work with accessing nested json data (and fields can sometimes be emtpy).
Here is an example of struct:
type SomeJson struct {
status string `json:"status"`
message string `json:"message"`
someMoreData []struct {
constant bool `json:"constant,omitempty"`
inputs []struct {
name string `json:"name"`
type string `json:"type"`
} `json:"inputs,omitempty"`
Name string `json:"name,omitempty"`
Outputs []struct {
Name string `json:"name"`
Type string `json:"type"`
} `json:"outputs,omitempty"`
I'm able to unmarshal the json data and access the top level fields (such as status and message), but am having trouble accessing any data under the someMoreData field. I understand this field is a (I assume an unknown) map of structs, but only have experience working with basic single level json blobs.
For reference this is the code I have to unmarshal the json and am able to access the top level fields.
someData := someJson{}
json.Unmarshal(body, &someData)
So what is exactly the best to access some nested fields such as inputs.name or outputs.name?
to iterate over your particular struct you can use:
for _, md := range someData.someMoreData {
println(md.Name)
for _, out := range md.Outputs {
println(out.Name, out.Type)
}
}
to access specific field:
someData.someMoreData[0].Outputs[0].Name
Couple of things to note:
The struct definition is syntactically incorrect. There are couple of closing braces missing.
type is a keyword.
The status and message and other fields with lower case first letter fields are unexported. So, the Json parser will not throw error, but you will get zero values as output. Not sure that's what you observed.
someMoreData is an array of structs not map.

Unmarshaling JSON into struct but converting values into required dtypes

I am using a JSON API for which I have to parse it into a struct. However, the API returns all values, even numbers, as strings and I need them to be in the format of numbers. So currently, I have a struct which has member fields which are all strings and after I have parsed the data, I loop through the entries to convert the values and add them to a new struct which has the specific entries in float or int values.
Is there any way to do the parsing and do type conversion in one go without having to use an intermediary struct representation from which to convert the values into the desired data types?
Example Code
str := []byte(`
{
"name": "Jim Burnham",
"age": "34",
"dob_day": "22",
"dob_month": "3",
"dob_year": "1984"
}
`)
Here is a sample JSON declaration of a response from an API. Notice how the age, day, month and year are returned as strings rather than integers. Now I declare a struct with the desired fields with JSON tags to map the values correctly:
type person struct {
Name string `json:"name"`
Age int `json:"age"`
DobDay int `json:"dob_day"`
DobMonth int `json:"dob_month"`
DobYear int `json:"dob_year"`
}
Then I declare an instance of the person struct and use the json package to unmarshal it into the instance of the struct:
var p person
_ = json.Unmarshal(str, &p)
fmt.Println(p)
But when I print out the person, the following output is generated:
{Jim Burnham 0 0 0 0}
As you can see, the string has been parsed correctly but the other integer fields remain at their default Golang initialized value. However, when I change the struct definition to :
type person struct {
Name string `json:"name"`
Age string `json:"age"`
DobDay string `json:"dob_day"`
DobMonth string `json:"dob_month"`
DobYear string `json:"dob_year"`
}
I get the following output:
{Jim Burnham 34 22 3 1984}
This means that currently, I have to define a raw struct which parses the information in the format of a string but then define another struct with the desired dtypes and reassign and convert the values separately, which produces untidy code as well. However, this is just one case but in my use case, there are likely thousands or even sometimes millions of such values and it seems to be inefficient, even for a compiled language. This is why I am asking for solutions for such a problem.
As explained well by #mkopriva at this link: https://play.golang.org/p/klHYlMQyb_V

How to modify big JSON file

I have a large json file with multiple levels of nesting. Now I need to modify the value of each key in this file with the Go code. I know of two methods: the first is to obtain each key and then modify its value, but there is no doubt that this method is too complicated and prone to errors. The second method is to serialize the entire json file into a struct, then modify the struct field, and then deserialize it. However, this case needs to define a struct of several hundred lines, which is also very complicated.
Is there any other way?
for example my json is like this, but more bigger, 100+ lines :
{
"user": [{
"cdb_id":"",
"firstname":"Tom",
"lastname":"Bradley",
"phone":14155555555,
"email":"tom#gmail.com",
"address":[{
"street":"4343 shoemaker ave",
"city":"Brea",
"zip":"92821",
"country":"USA"
}],
"authenticators":[{
"name":"Lisa Hayden",
"phone":15625555555
},{
"name":"Pavan M",
"phone":17145555555
}],
"voice_sig":"242y5-4546-555kk54-437879ek545",
"voicesig_created_time":"2017-08-02T21:27:44+0000",
"status":"verified"
}]
}
I need modify "cdb_id"/"lastname"/"street"/"phone"/ "voice_sig".....all these keys' value, Except make a struct or get the keys' value one by one and modify, do i have any other way?
The new values for those keys will be POST request from Web Pages.
You can use json pointer:
https://godoc.org/github.com/go-openapi/jsonpointer
Or, you can read it in a map[string]interface{} and work your way through, but that gets tedious.
Now my way is use this website, switch my Json to struct, and modify one by one. But it just think this is not so good way, so i am eagering for a better way.
http://json2struct.mervine.net/
type MyJsonName struct {
User []struct {
Address []struct {
City string `json:"city"`
Country string `json:"country"`
Street string `json:"street"`
Zip string `json:"zip"`
} `json:"address"`
Authenticators []struct {
Name string `json:"name"`
Phone int `json:"phone"`
} `json:"authenticators"`
CdbID string `json:"cdb_id"`
Email string `json:"email"`
Firstname string `json:"firstname"`
Lastname string `json:"lastname"`
Phone int `json:"phone"`
Status string `json:"status"`
VoiceSig string `json:"voice_sig"`
VoicesigCreatedTime string `json:"voicesig_created_time"`
} `json:"user"`
}

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"`
}

My structures are not marshalling into json [duplicate]

This question already has answers here:
json.Marshal(struct) returns "{}"
(3 answers)
Closed 3 years ago.
I am using Go 1.0.3 on Mac OS X 10.8.2, and I am experimenting with the json package, trying to marshal a struct to json, but I keep getting an empty {} json object.
The err value is nil, so nothing is wrong according to the json.Marshal function, and the struct is correct. Why is this happening?
package main
import (
"encoding/json"
"fmt"
)
type Address struct {
street string
extended string
city string
state string
zip string
}
type Name struct {
first string
middle string
last string
}
type Person struct {
name Name
age int
address Address
phone string
}
func main() {
myname := Name{"Alfred", "H", "Eigenface"}
myaddr := Address{"42 Place Rd", "Unit 2i", "Placeton", "ST", "00921"}
me := Person{myname, 24, myaddr, "000 555-0001"}
b, err := json.Marshal(me)
if err != nil {
fmt.Println(err)
}
fmt.Println(string(b)) // err is nil, but b is empty, why?
fmt.Println("\n")
fmt.Println(me) // me is as expected, full of data
}
You have to make the fields that you want to marshal public.
Like this:
type Address struct {
Street string
Extended string
City string
State string
Zip string
}
err is nil because all the exported fields, in this case there are none, were marshalled correctly.
Working example: https://play.golang.org/p/9NH9Bog8_C6
Check out the docs http://godoc.org/encoding/json/#Marshal
Note that you can also manipulate what the name of the fields in the generated JSON are by doing the following:
type Name struct {
First string `json:"firstname"`
Middle string `json:"middlename"`
Last string `json:"lastname"`
}
JSON library cannot view the fields in a struct unless they are public. In your case,
type Person struct {
name Name
age int
address Address
phone string
}
the fields name, age, address and phone are not public (start with a small letter). In golang, variables/functions are public, when they start with a capital letter. So for this to work, your struct needs to look something like this:
type Person struct {
Name Name
Age int
Address Address
Phone string
}