How to render a json string from bson document [duplicate] - json

This question already has answers here:
How to convert bson to json effectively with mongo-go-driver?
(1 answer)
convert result into JSON without structs using mongo-go-driver
(1 answer)
How can I get JSON from BSON without my keys all being named "Key"?
(1 answer)
Closed 3 years ago.
I am struggling to create a valid JSON string from a BSON document in Go for an API.
Let's say I have an object like this:
type MyObject struct {
Name string
}
I call my database which returns to me a cursor containing many documents as: [{"Name": "object_name"}, ...]
I am able to retrieve all the documents via a loop like
for cur.Next(ctx) {
var obj MyObject
err := cur.Decode(&obj)
//then display error if there's one
}
And now I would like to end up with a JSON string containing all the documents my database returned in order to send it via HTTP.
Because, if use I fmt.Println(obj)I end up with something like this: [{object1_name} {object2_name} ...] which is, according to me, not a valid format that I can use for an API.
I know json.Marshal(obj) can actually encode to valid JSON and I can decode it with os.Stdout.Write(obj) but I didn't manage to store this valid string in a variable. How can I manage to do this?

From Golang documentation for json package
package main
import (
"encoding/json"
"fmt"
)
func main() {
type ColorGroup struct {
ID int `json:"id"`
Name string `json:"name"`
Colors []string `json:"colors"`
}
group := ColorGroup{
ID: 1,
Name: "Reds",
Colors: []string{"Crimson", "Red", "Ruby", "Maroon"},
}
b, err := json.Marshal(group)
if err != nil {
fmt.Println("error:", err)
} else {
str := string(b)
fmt.Println("stringified json is:", str)
}
}
Output
stringified json is: {"id":1,"name":"Reds","colors":["Crimson","Red","Ruby","Maroon"]}
The json.Marshal return two values - a byte array and error
If error is nil then you can obtain the string by converting byte array to string using
str := string(b)

Related

How to unmarshal raw CSV response into a struct? [duplicate]

This question already has an answer here:
Convert byte slice to io.Reader
(1 answer)
Closed 2 months ago.
I have a body response that I can only get Byte responses. This bytes encode a csv-like response. Something like:
element_a,element_b,element_c
cooper,claus,active
carlos,saldanha,inactive
robert,jesus,active
Lets say then that I have the struct that looks like this:
type ESResponse struct {
ElementA string `csv:"element_a"`
ElementB string `csv:"element_b"`
ElementC string `csv:"element_c"`
}
I would like to unmarshal the byte response so then I'm able to access its elements.
What I've been doing is the following:
var actualResult ESResponse
body := util.GetResponseBody() // this is where the byte response comes from.
in := string(body[:]) // here I transform it to a string but I trully think this is not the best way.
err = gocsv.Unmarshal(in, &actualResult)
I've been using this library here: https://pkg.go.dev/github.com/gocarina/gocsv#section-readme but I'm unable to understand the error I get which is:
cannot use in (variable of type string) as io.Reader value in argument to gocsv.Unmarshal: string does not implement io.Reader (missing method Read)
It means, that in argument must implement interface io.Reader, but you argument's type is string, which doesn't. So if you want to deserialize value from string, you can do this:
body := `
element_a,element_b,element_c
cooper,claus,active
carlos,saldanha,inactive
robert,jesus,active`
var actualResult []ESResponse
in := strings.NewReader(body)
err := gocsv.Unmarshal(in, &actualResult)
or gocsv.Unmarshal(bytes.NewReader([]byte(body)), &actualResult) to deserialize from bytes array

How to convert escaped json into a struct [duplicate]

This question already has answers here:
decode json including json encoded strings
(1 answer)
Unmarshaling a stringified json
(1 answer)
Closed 1 year ago.
I am having trouble converting an escaped json object into a struct.
The main problem I am facing is the escaped json for the sources field.
The following data is how it's being saved.
{
"key": "123",
"sources": "{\"1a\":\"source1a\",\"2b\":\"source2b\",\"3c\":\"source3c\",\"default\":\"sourcex\"}"
}
type config struct {
Key string `json:"key" validate:"required"`
Sources ???? `json:"sources" validate:"required"`
}
I then will have a source value and would like to check if my value is found in the json.
If my value is "1a" return "source1a", etc.
I'm trying to write this in a unit test as well.
Some might do a custom unmarshal method, but I think it's easier just to do two passes:
package main
import (
"encoding/json"
"fmt"
)
const s = `
{
"key": "123",
"sources": "{\"1a\":\"source1a\",\"2b\":\"source2b\",\"3c\":\"source3c\",\"default\":\"sourcex\"}"
}
`
func main() {
var t struct{Key, Sources string}
json.Unmarshal([]byte(s), &t)
m := make(map[string]string)
json.Unmarshal([]byte(t.Sources), &m)
fmt.Println(m) // map[1a:source1a 2b:source2b 3c:source3c default:sourcex]
}

[Go]: Parsing JSON [duplicate]

This question already has answers here:
Lowercase JSON key names with JSON Marshal in Go
(4 answers)
Closed 5 years ago.
What I am trying to do
I am parsing a JSON HTTP response based on this answer to a similar question. My code is able to parse the JSON without any error but is unable to read the values and store them in the provided variable.
This has been puzzling me for the last 2 hours and it might be due to a trivial reason that I am overlooking here.
CODE
type ImporterResponse struct {
results []packagemeta `json:"results"`
}
type packagemeta struct {
path string `json:"path"`
synopsis string `json:"synopsis,omitempty"`
count int `json:"import_count,omitempty`
}
func main() {
res := []byte(`{"results":[{"path":"4d63.com/randstr/lib/randstr","import_count":0,"synopsis":"Package randstr generates random strings (e.g."},{"path":"bitbucket.org/pcas/tool/mathutil","import_count":0}]}`)
fmt.Println("Decoding the JSON")
r := bytes.NewReader(res)
decoder := json.NewDecoder(r)
packageimporters := &ImporterResponse{}
err := decoder.Decode(packageimporters)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Packageimporters: %+v", packageimporters)
fmt.Println(len(packageimporters.results))
}
Link to Playground: https://play.golang.org/p/NzLl7Ujo2IJ
What I want:
How to fix this?
Why is no error message raised if JSON is not parsed properly?
P.S: I understand that this question has been asked before and there are possible solutions available but none of them work for me. Hence, I have made this post.
You need to make your struct fields exported, otherwise the json package cannot access them.
Please read JSON and go for more details, specifically this paragraph:
The json package only accesses the exported fields of struct types
(those that begin with an uppercase letter). Therefore only the the
exported fields of a struct will be present in the JSON output.
And this one for more details:
How does Unmarshal identify the fields in which to store the decoded
data? For a given JSON key "Foo", Unmarshal will look through the
destination struct's fields to find (in order of preference):
An exported field with a tag of "Foo" (see the Go spec for more on
struct tags),
An exported field named "Foo", or
An exported field
named "FOO" or "FoO" or some other case-insensitive match of "Foo".
So your struct should really be:
type Packagemeta struct {
Path string `json:"path"`
Synopsis string `json:"synopsis,omitempty"`
Count int `json:"import_count,omitempty`
}

unmarshal generic json in Go [duplicate]

This question already has answers here:
JSON and dealing with unexported fields
(2 answers)
(un)marshalling json golang not working
(3 answers)
json.Marshal(struct) returns "{}"
(3 answers)
Printing Empty Json as a result [duplicate]
(1 answer)
Parsing JSON in Golang doesn't Populate Object [duplicate]
(1 answer)
Closed 10 months ago.
I'm a new Go programmer (From Java) and I would like to reproduce a generic way which is esay to use in Java.
I want to create some function which allow me to do an Unmarshal on a JSON string in order to avoid code duplicity.
This is my current code which is not working :
type myStruct1 struct {
id string
name string
}
func (obj myStruct1) toString() string {
var result bytes.Buffer
result.WriteString("id : ")
result.WriteString(obj.id)
result.WriteString("\n")
result.WriteString("name : ")
result.WriteString(obj.name)
return result.String()
}
func main() {
content := `{id:"id1",name="myName"}`
object := myStruct1{}
parseJSON(content, object)
fmt.Println(object.toString())
}
func parseJSON(content string, object interface{}) {
var parsed interface{}
json.Unmarshal([]byte(content), &parsed)
}
This code, on run, returns me this :
id :
name :
Do you have any idea ?
Thanks
The issue is you want to write to a generic type? You probably want a string map. This works with BSON anyways:
var anyJson map[string]interface{}
json.Unmarshal(bytes, &anyJson)
You'll be able to access the fields like so:
anyJson["id"].(string)
Don't forget to type assert your values, and they must be the correct type or they'll panic. (You can read more about type assertions on the golang site)
To parse "generic JSON" when you have no idea what schema it has:
var parsed any
err := json.Unmarshal(jsonText, &parsed)
The returned any in parsed will be a map[string]any or []any or nil or single values float64, bool, string.
You can test the type and react accordingly.
import (
"encoding/json"
"fmt"
)
func test(jsonText []byte) {
// parsing
var parsed any
err := json.Unmarshal(jsonText, &parsed)
if err != nil {
panic(err) // malformed input
}
// type-specific logic
switch val := parsed.(type) {
case nil:
fmt.Println("json specifies null")
case map[string]any:
fmt.Printf("id:%s name:%s\n", val["id"], val["name"])
case []any:
fmt.Printf("list of %d items\n", len(val))
case float64:
fmt.Printf("single number %f\n", val)
case bool:
fmt.Printf("single bool %v\n", val)
case string:
fmt.Printf("single string %s\n", val)
default:
panic(fmt.Errorf("type %T unexpected", parsed))
}
}
Unmarshal will only set exported fields of the struct.
Which means you need to modify the json struct to use capital case letters:
type myStruct1 struct {
Id string
Name string
}
The reason behind this is that the json library does not have the ability to view fields using reflect unless they are exported.
You have to export your fields:
type myStruct1 struct {
Id string
Name string
}
See Exported Identifiers from documentation.
There are a few changes you need to make in your code to make it work:
The function json.Unmarshal can only set variables inside your struct which are exported, that is, which start with capital letters. Use something like ID and Name for your variable names inside myStruct1.
Your content is invalid JSON. What you actually want is {"ID":"id1","Name":"myName"}.
You're passing object to parseJSON but you're using parsed instead, not object. Make parseJSON receive a *myStruct (instead of an interface{}), and use that variable instead of parsed when unmarshalling the string. Also, always handle the error returns, like err := json.Unmarshal(content, object), and check err.
I'd suggest you to do the Golang Tour ;)
You can also set the file as an Object with dynamic properties inside another struct. This will let you add metadata and you read it the same way.
type MyFile struct {
Version string
Data map[string]interface{}
}

How to access interface fields on json decode?

I have a json document and I'm using a client which decodes the document in an interface (instead of struct) as below:
var jsonR interface{}
err = json.Unmarshal(res, &jsonR)
How can I access the interface fields? I've read the go doc and blog but my head still can't get it. Their example seem to show only that you can decode the json in an interface but doesn't explain how its fields can be used.
I've tried to use a range loop but it seems the story ends when I reach a map[string]interface. The fields that I need seem to be in the interface.
for k, v := range jsonR {
if k == "topfield" {
fmt.Printf("k is %v, v is %v", k, v)
}
}
The value inside the interface depends on the json structure you're parsing. If you have a json dictionary, the dynamic type of jsonR will be: map[string]interface{}.
Here's an example.
package main
import (
"encoding/json"
"fmt"
"log"
)
func main() {
a := []byte(`{"topfield": 123}`)
var v interface{}
if err := json.Unmarshal(a, &v); err != nil {
log.Fatalf("unmarshal failed: %s", err)
}
fmt.Printf("value is %v", v.(map[string]interface{})["topfield"])
}
Parsing json like this can be very difficult. The default type of a parse is map[string]interface{}. The Problem arises when you have another complex data structure within the main json(like another list or object). The best way to go about decoding json is defining a struct to hold data. Not only will the values be of the correct type but you can extract the specific data you actually care about.
Your struct can look like this:
type Top struct {
Topfield int `json:"topfield"`
}
which can be decoded like this:
a := []byte(`{"topfield": 123}`)
var data Top
json.Unmarshal(a, &data) //parse the json into data
now you can use regular struct operations to access your data like this:
value := data.Topfield
json which contains more complex data can also be easyli decoded. Perhaps you have a list in your data somewhere, you can use a struct like the following to extract it:
type Data struct {
States []string `json:"states"`
PopulationData []Country `json:"popdata"`
}
type Country struct {
Id int `json:"id"`
LastCensusPop int `json:"lcensuspopulation"`
Gdp float64 `json:"gdp"`
}
such a structure can not only parse list but also parse objects withing fields.