Removing a specific element from a json array in golang - json

I tried a few options but with no results. If anyone knows some kind of solution it would be nice. I was trying with buger/jsonparser because of the parsing speed. Lets say i want to exclude object3 and assign it to MYVARIABLE
for exaple :
data:=[{object1}, {object2}, {object3}]
//this function iterates through the array
jsonparser.ArrayEach(data, func(key []byte, dataType jsonparser.ValueType, offset int, err error) {
MYVARIABLE:=key
return
})

Let's say that you have successfully parsed your data to struct.
And you would have an array of yourStruct []yourStruct, and assign the third element with empty struct like this :
yourStruct[2] = YourStruct{}
the third element is still there with empty value. And unfortunately in go you can't assign struct with nil value.
or you can convert the []byte of your data that has your json to string and iterate it over to the their element and remove it with empty char, but this would be an expensive approach.
As Kaedys said you can remove your array struct using slice like this :
yourStruct = yourStruct[:2]
fmt.Printf("resutl struct = %+v\n", yourStruct)

Related

Marshal map[string] interface{} but with tags

I know Go has a way to json.Marshal struct and also json.Marshal map[string]interface{}.
But when it marshals a struct, it can uses its json tags'. Is there a way, in standard or with another library to json.Marshal a map[string]interface{} and to pass it the same options that would have been stored in a field tag for a struct?
Actually there is a way, a bit tricky, but still.
You have to create a struct from reflect package.
You iterate over each element in your map and for each of them you create a struct field :
fields = append(fields, reflect.StructField{
Name: ,
Type: ,
Tag: ,
})
You can set the tags to whatever you want, meaning you can set json values, like the omitempty one.
Then you have to create the struct itself :
s := reflect.New(reflect.StructOf(fields))
Then another iteration over your map will be needed, to fill the struct with values.
s.Elem().FieldByName(name).Set(WhateverValue)
Finally you can pass your struct to json.Marshall(s.Interface()).

Dynamic Type in Unmarshal

I currently having the following problem:
I get a []byte / string via websocket which looks like
eventname {"JSON": "data", "In": "different formats"}
I split the string by the whitespace between the eventname and the JSON data and, depending on the eventname, I want to json.Unmarshal() the JSON data into a specific type or a var of a specific type, to make sure its all type safe.
So I would probably have a map which holds all the possible eventnames and the corresponding type for the JSON data, but im not sure how I would save a type, maybe by reference or by the stringified name?
type EventTypeList map[string]*interface{}
or
type EventTypeList map[string]string
So I can lookup if the event is in the EventTypeList and then let the Unmarshal func parse the data into the type from the map.
So basicly instead of the specific type "SpecificData":
type SpecificData struct {
JSON string
In string
}
socketData := SpecificData{}
err := json.Unmarshal(jsonData, &socketData)
I want to dynamically create the socketData var by the type from the EventTypeList
socketData := [dynamically determine this Type from EventTypeList]{}
After I parsed the data into that type, I want to call all listeners for that event and give them the socketData with the right type, so they can work with the expected data.
But im really not sure how I would accomplish this, if this is even possible or if this is even the right way...
Thanks for any help!
Ok, after reasearching, I think what I wanted to achive is not possible, because the type needs to be know at compile time, as it has been mentioned here:
Golang: cast an interface to a typed variable dynamically
But I think I can just pass the raw JSON string to the listener callback and Unmarshal the data in that function where the type of the data is known.
Thanks for all contributions!

Dynamically Allocating Stucture

I have a struct:
type person struct{
FirstN [10]byte
Last Name [10]byte
Address [15]byte
zip [6]byte
}
Then I have Map
xyz = [01:aaaaaaaaaabbbbbbbbbbccccccccccccccc123456]
This map is exactly the same as my struct. Basically if I overlay my structure with the string in the map it is an exact match.
I am trying to get a JSON string for this data, using Marshal. But for that (as I understand it) I need to update the data in the map into the struct and then pass the structure pointer to Marshal
But I cannot find any way to get the data from the map with key '01' which is a string and initialize my structure with it. I do not want to add a code to update each field in the structure by parsing the string from the map. Is there a way to do it or hardcoding is the only option.
Also is there a way to create a JSON string from a map string directly?
That's not json data. However, the binary.Read function will decode arbitrary fixed sized values from a binary stream following the struct layout.
data := []byte("aaaaaaaaaaaaaaaaaaaaccccccccccccccc123456")
err := binary.Read(bytes.NewReader(data), binary.LittleEndian, &p)
https://play.golang.org/p/-I_XhUCvNN

Unmarshal inconsistent JSON

I have JSON (that I cannot control) like this:
{
"foo1":{
"a":{
"up":10,
"down":5
}
},
"foo2":{
"a":{
"up":1,
"down":1
}
},
"bar":{
"up":11,
"down":6
}
}
"foo1" and "foo2" are dynamic.
How can I properly unmarshal this structure in go?
It would be okay if I could just tell go to not try to deserialize "bar" (the inconsistent property).
Go will by default ignore fields unspecified in the struct you unmarshal into.
In this case, your structure would be set up like this:
type NestedProp2 struct {
Up int
Down int
}
type NestedProp struct {
A NestedProp2
}
type Prop struct {
Foo1 NestedProp
Foo2 NestedProp
}
When you call the the json.Unmarshal function, the extra property will not be deserialized:
var prop Prop
err := json.Unmarshal(jsonBlob, &prop)
if err != nil {
fmt.Println("error:", err)
}
fmt.Printf("%+v", prop)
So you get the following output:
{Foo1:{A:{Up:10 Down:5}} Foo2:{A:{Up:1 Down:1}}}
You can see it in action here.
You said:
I have JSON (that I cannot control)
So to what extent you could control? Here I could provide you with some scenario, and hope some of them match your purpose :)
Remember the general rule first:
In Golang, if a JSON key failed to find a matched field in struct, it will not be unmarshalled.
This means, for a key name in a JSON struct, when unmarshalling, it will look for a field in a golang struct at the same level with the same name case-insensitively. If this search failed, this key won't be unmarshalled.
For example, a key named foo1 will look for a field name foo1 in a golang struct at the same indent level. However it also matches with Foo1 or FoO1, since this matching is case-insensitive.
Remember, you could use field tag to specify the field name as well. Please take a look at the official page.
The value of some of the JSON fields are not consistent, and they could be ignored.
This is the case #gnalck solved in his answer. According to the general rule, if those inconsistent field failed to find a match, they will not be unmarshalled. Therefore, just don't put those inconsistent fields in the struct and you will be fine.
The value of some of the JSON fields are not consistent, but they could not be ignored.
In this case, #gnalck failed since those fields could not be ignored. Now a better way is to unmarshal bar into a json.RawMessage, so that you could unmarshal later.
The keys of the JSON object is undetermined, and their value is undetermined as well.
In this case, we could unmarshal the whole JSON object into a map[string]json.RawMessage, and unmarshal each fields later. When unmarshalling to a map, you could iterate through the map to get all the fields, and unmarshal them into a proper struct later.

Write struct to csv file

What is an idiomatic golang way to dump the struct into a csv file provided? I am inside a func where my struct is passed as interface{}:
func decode_and_csv(my_response *http.Response, my_struct interface{})
Why interface{}? - reading data from JSON and there could be a few different structs returned, so trying to write a generic enough function.
an example of my types:
type Location []struct {
Name string `json: "Name"`
Region string `json: "Region"`
Type string `json: "Type"`
}
It would be a lot easier if you used a concrete type. You'll probably want to use the encoding/csv package, here is a relevant example; https://golang.org/pkg/encoding/csv/#example_Writer
As you can see, the Write method is expecting a []string so in order to generate this, you'll have to either 1) provide a helper method or 2) reflect my_struct. Personally, I prefer the first method but it depends on your needs. If you want to go route two you can get all the fields on the struct an use them as the column headers, then iterate the fields getting the value for each, use append in that loop to add them to a []string and then pass it to Write out side of the loop.
For the first option, I would define a ToSlice or something on each type and then I would make an interface call it CsvAble that requires the ToSlice method. Change the type in your method my_struct CsvAble instead of using the empty interface and then you can just call ToSlice on my_struct and pass the return value into Write. You could have that return the column headers as well (meaning you would get back a [][]string and need to iterate the outer dimension passing each []string into Write) or you could require another method to satisfy the interface like GetHeaders that returns a []string which is the column headers. If that were the case your code would look something like;
w := csv.NewWriter(os.Stdout)
headers := my_struct.GetHeaders()
values := my_struct.ToSlice()
if err := w.Write(headers); err != nil {
//write failed do something
}
if err := w.Write(values); err != nil {
//write failed do something
}
If that doesn't make sense let me know and I can follow up with a code sample for either of the two approaches.