jsonparser access fields by index - json

i have problem to access fields by index. this library https://github.com/buger/jsonparser
example from https://github.com/buger/jsonparser:
// Or use can access fields by index!
jsonparser.GetInt("person", "avatars", "[0]", "url")
My code:
package main
import (
"github.com/buger/jsonparser"
"fmt"
)
func main () {
data := []byte(`{
"person": {
"name": {
"first": "Leonid",
"last": "Bugaev",
"fullName": "Leonid Bugaev"
},
"github": {
"handle": "buger",
"followers": 109
},
"avatars": [
{
"url": "https://avatars1.githubusercontent.com/u/14009?v=3&s=460",
"type": "thumbnail"
}
]
},
"company": {
"name": "Acme"
}
}`)
fmt.Println(jsonparser.GetInt(data, "person", "[2]", "[0]", "url"))
}
result in terminal:
0 Key path not found

Person is not an array so you can not access it by index.

Related

Golang iterate over nested struct

i want to iterate over a nested json struct in golang. The issue is, i do not exactly know how nested the structure will be, becuase there are multiple jsons. In this case for example the output should be:
"available": false
"type": "foo"
"name": "foo"
"street": "foo"
....
Is that possible?
{
"informations": {
"available": false,
"provide": {
"informations": {
"customer": {
"type": "foo",
"address": {
"name": "foo",
"street": "foo",
"zipcode": "123",
"city": "foo"
}
}
}
}
}
}
I think you can do this with a map[string]interface{}. Because, as you said that you don't know exactly the structure of the JSON. But, again, you need to know the JSON structure each time while extracting data. Also, you need to do type assertion for inner map[string]interface{}. You can look at the answer from here for type assertion.
Here's the example code that I wrote:
package main
import (
"encoding/json"
"fmt"
)
var j = `{
"informations": {
"available": false,
"provide": {
"informations": {
"customer": {
"type": "foo",
"address": {
"name": "foo",
"street": "foo",
"zipcode": "123",
"city": "foo"
}
}
}
}
}
}`
func main() {
var data map[string]interface{}
err := json.Unmarshal([]byte(j), &data)
if err != nil {
fmt.Println(err.Error())
return
}
fmt.Println(data["informations"])
information := data["informations"]
provide := information.(map[string]interface{})["provide"]
fmt.Println(provide)
}
Output will be:
map[available:false provide:map[informations:map[customer:map[address:map[city:foo name:foo street:foo zipcode:123] type:foo]]]]
map[informations:map[customer:map[address:map[city:foo name:foo street:foo zipcode:123] type:foo]]]
Go Playground

How to create hierarchical json structure by slice string path

I'm building a backend for a file manager written in Go.
I'm looking for a way to make an example slice string path.
sliceStr := []string{
"/file_A.txt",
"/folder_B/file_B.txt",
"/folder_C/sub_folder_C/file_C.txt",
"/folder_C/sub_folder_C/file_C_2.txt",
}
to create an api that returns a hierarchical json structure to pass to the frontend using Devextreme FileManager. Like below
[
{
"name": "file_A.txt",
"isDirectory": false
},
{
"name": "folder_B",
"isDirectory": true,
"items": [
{
"name": "file_B.txt",
"isDirectory": false
}
]
},
{
"name": "folder_C",
"isDirectory": true,
"items": [
{
"name": "sub_folder_C",
"isDirectory": true,
"items": [
{
"name": "file_C.txt",
"isDirectory": false,
},
{
"name": "file_C_2.txt",
"isDirectory": false
}
]
}
]
}
]
you can try this method
join the slice into a byte array
Implement you own json UnmarshalJSON
type Yourstruct struct {
.......
}
func (t *Yourstruct ) UnmarshalJSON(data []byte) error
demo case

Manipulating mongodb's bson.D output format

Im using FindOne to query one row of data (single document):
package main
import (
"context"
"fmt"
"github.com/fatih/color"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
func mongoDbFindOne(key, value string) bson.D {
var result bson.D
_ = Collection.FindOne(context.TODO(), bson.D{{key, value}}).Decode(&result)
color.Green("[+] Found: %+v\n", result)
return result
}
And this a small part of how the result is shown:
[
{
"Key": "_id",
"Value": "1600540844649"
},
{
"Key": "hostname",
"Value": "DESKTOP-xxxxxx"
},
{
"Key": "cmdLine",
"Value": []
},
{
"Key": "pid",
"Value": 4816
}
]
But this how i want it to be:
[
{
"_id": "1600540844649"
},
{
"hostname": "DESKTOP-xxxxxx"
},
{
"cmdLine": []
},
{
"pid": 4816
}
]
Or:
[
{
"_id": "1600540844649",
"hostname": "DESKTOP-xxxxxx",
"cmdLine": [],
"pid": 4816,
}
]
What should i do? I have searched through SO and google but no luck. Should i use struct or creating any objects? I also searched for saving/converting bson to json but there is solution to it.
I found the solution myself:
Using bson.M instead of bson.D solved my issue:
import (
"context"
"fmt"
"github.com/fatih/color"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
func mongoDbFindOne(key, value string) bson.M {
var result bson.M
_ = Collection.FindOne(context.TODO(), bson.M{key:value}).Decode(&result)
color.Green("[+] Found: %+v\n", result)
return result
}

Enumerate slice entries

If I have this output
Stuff {
"Items": [
{
"title": "test1",
"id": "1",
},
{
"title": "test",
"id": "2",
},
],
"total": 19
},
}
But want this instead:
stuff {
"Items": [
1:{
"title": "test1",
"id": "1",
},
2:{
"title": "test",
"id": "2",
},
],
"total": 19
},
}
Currently, my structs are build like this:
Stuff struct {
Items []Items `json:"items"`
Total int `json:"total"`
} `json:"stuff"`
type Items struct {
Title string `json:"title"`
ID string `json:"id"`
}
I initiate a slice by:
stuff := make([]Items, 10) // Lets say I have 10 entries
And append by:
Stuff.Items = stuff
Stuff.Total = len(Stuff.Items)
Now I am unsure on how to numerate that. So for every item entries, there should be a number, starting from 1 - 10 (In this example)
Given your Stuff and Items type declarations, here's a simple data structure and its JSON dump:
s := Stuff{Items: []Items{Items{"test1", "1"}, Items{"test2", "2"}}, Total: 10}
j, err := json.MarshalIndent(s, "", " ")
if err != nil {
log.Fatal(err)
}
fmt.Println(string(j))
JSON:
{
"items": [
{
"title": "test1",
"id": "1"
},
{
"title": "test2",
"id": "2"
}
],
"total": 10
}
To see what you want instead, there's no magic json package call to do that. You'll have to create a new data structure that reflects the structure of your desired output.
In this case a simple map will do:
m := make(map[string]Items)
for _, item := range s.Items {
m[item.ID] = item
}
And now if you JSON-dump this map, you get:
{
"1": {
"title": "test1",
"id": "1"
},
"2": {
"title": "test2",
"id": "2"
}
}
Note that I'm not wrapping it with Stuff now, because Stuff has different fields. Go is statically typed, and each struct can only contain the fields you declared it to have.

Go structure for unmarshalling a JSON array

So I have some JSON (courtesy of the PetFinder API) that has a JSON array "pet". I want to unmarshal from it, using the "encoding/json" package, a slice of pet structs. What would this kind of structure look like? I can't find any examples of how the unmarshall function handles JSON arrays.
Here's what I was planning to do once I had a proper struct:
pfetch := new(PetsFetcher) // where PetsFetcher is the struct im asking for
err := json.Unmarshal(body, &pfetch)
And here's the json that is in body (in the form of a slice of ascii bytes):
{
"petfinder": {
"lastOffset": {
"$t": 5
},
"pets": {
"pet": [
{
"options": {
"option": [
{
"$t": "altered"
},
{
"$t": "hasShots"
},
{
"$t": "housebroken"
}
]
},
"breeds": {
"breed": {
"$t": "Dachshund"
}
}
},
{
"options": {
"option": {
"$t": "hasShots"
}
},
"breeds": {
"breed": {
"$t": "American Staffordshire Terrier"
}
},
"shelterPetId": {
"$t": "13-0164"
},
"status": {
"$t": "A"
},
"name": {
"$t": "HAUS"
}
}
]
}
}
}
Thanks in advance.
I really have no idea what those $t attributes are doing there in your JSON, so let’s answer your question with a simple example. To unmarshal this JSON:
{
"name": "something",
"options": [
{
"key": "a",
"value": "b"
},
{
"key": "c",
"value": "d"
},
{
"key": "e",
"value": "f"
},
]
}
You need this Data type in Go:
type Option struct {
Key string
Value string
}
type Data struct {
Name string
Options []Option
}
You can unmarshal a javascript array into a slice. The marhsal/unmarshalling rules are described under Marshal in the json package.
To unmarshal keys that look like "$t", you'll have to annotate the struct that it'll unpack into.
For example:
type Option struct {
Property string `json:"$t,omitempty"`
}
It may be that the $t that appear are a mistake, and are supposed to be keys in a dictionary.