Getting file content into a multidimensional string var - arrays

I'm using the fsnotify packet to wait for changes in a json file.
I have two problems with this code. The first one is regarding the info returned by ReadFile function. Looks like when I print something returned by the function is empty.
Second issue is regarding the fsnotify that is not reading the file the first time unless i do some modification on the content. I must read the file from the beggining as well.
type Information struct {
Info []Info `json:"info"`
}
type Info struct {
Type string `json:"type"`
News []New `json:"news"`
}
type New struct {
Name string `json:"name"`
Read bool `json:"read"`
}
func ReadFile(file_name string) *Information {
jsonFile, err := os.Open(file_name)
if err != nil {
fmt.Println(err)
}
fmt.Println("Successfully Opened file_name.json")
defer jsonFile.Close()
byteValue, _ := ioutil.ReadAll(jsonFile)
var infor Information
json.Unmarshal(byteValue, &infor)
return &infor
}
// main function
func main() {
// read json file using fsnotify to wait for changes
watcher, err := fsnotify.NewWatcher()
if err != nil {
panic(err)
}
err = watcher.Add(file_json)
if err != nil {
panic(err)
}
for {
select {
case ev, ok := <-watcher.Events:
log.Println("event:", ev)
if !ok {
return
}
if ev.Op&fsnotify.Write == fsnotify.Write {
data := ReadFile(file_name)
fmt.Print("INFORMATION ABOUT FILE:\n")
for _, info := range data.Info {
fmt.Printf("Info type: %s\n", info.Type) // Here is not printing the result of info.Type
for _, news := range info.News {
fmt.Printf("News Name: %s\n", news.Name) // Here is not printing even "News Name:" or News Read:"
fmt.Printf("News Read: %s\n", strconv.FormatBool(news.Read))
}
}
}
case err := <-watcher.Errors:
log.Println("error:", err)
}
}
}
This is the json file:
{
    "info": [
      {
        "type": "general",
        "news": [
          { "name": "abc",  "read": true },
          { "name": "def",  "read": true }
        ]
      },
{
"type": "confidential",
"news": [
{ "name": "xxx", "read": false },
{ "name": "yyy", "read": false }
]
},
]
}

type Information struct {
Info []Info `json:"info"`
}
type Info struct {
Type string `json:"type"`
News []New `json:"news"` // Here should be a slice define.
}
type New struct {
Name string `json:"name"`
Read bool `json:"read"`
}
func ReadFile(file_name string) *Information {
jsonFile, err := os.Open(file_name)
if err != nil {
fmt.Println(err)
}
fmt.Println("Successfully Opened file_name.json")
defer jsonFile.Close()
byteValue, _ := ioutil.ReadAll(jsonFile)
var infor Information
json.Unmarshal(byteValue, &infor)
return &infor
}
func main() {
data := ReadFile("./data.json")
for _, news := range data.Info {
for _, v := range news.News {
name := v.Name
// Add you want to do
fmt.Println(name)
}
}
}
You can not get like this:
getInfo = [general][abc, true, def, true]
[confidential][xxx, false, yyy, false]

Related

Golang - How to iterate through two slices at the same time

I'm trying to write a function that takes in a struct, and within that there are two nested structs. I need to iterate through both nested structs, find the "Service" field and remove the prefixes that are separated by the '-'.
I've written a function that does what I want it to and removes the prefixes, however it consists of two for loops that loop through the two separate structs. Is their a way for me to write this function in a way that it loops through the structs in one for loop?
Here are the structs:
var myJson = `
{
"ID": "hgfd5432",
"Greeting": "Welcome!",
"ServiceNames": [
{
"Service": "sevice-name-service1",
"Version": "1.8"
},
{
"Service": "sevice-name-service2",
"Version": "1.8"
},
{
"Service": "sevice-name-service3",
"Version": "1.9"
},
{
"Service": "sevice-name-service4",
"Version": "0.6"
}
],
"Services": [
{
"Service": "sevice-name-service5",
"Version": "1.8"
}
],
"BusinessUnit": "Unit 1",
"Queue": "UK73_Advocacy_PCCT",
"Input": "Default",
}`
type Profile struct {
ProfileId string `json:"ID"`
Input string `json:"Input"`
ParentProfile string `json:"ParentProfile"`
Persona string `json:"Persona"`
BusinessUnit string `json:"BusinessUnit"`
Greeting string `json:"Greeting"`
Queue string `json:"Queue"`
ServiceNames []ServiceKey `json:"ServiceNames"`
Services []ServiceInfo `json:"Services"`
And here is the function:
func removePrefix(inputParameters *Profile) error {
for i := 0; i < len(inputParameters.ServiceNames); i++ {
a := strings.Split(inputParameters.ServiceNames[i].Service, "-")
s := a[len(a)-1]
inputParameters.ServiceNames[i].Service = s
}
for i := 0; i < len(inputParameters.Services); i++ {
a := strings.Split(inputParameters.Services[i].Service, "-")
s := a[len(a)-1]
inputParameters.Services[i].Service = s
}
return nil
One way you can do this is,
serviceNamesLength := len(inputParameters.ServiceNames)
servicesLength := len(inputParameters.Services)
maxLength := serviceNamesLength
if servicesLength > maxLength {
maxLength = servicesLength
}
for i := 0; i < maxLength; i++ {
if i < servicesLength {
// services stuff
}
if i < serviceNamesLength {
// services names stuff
}
}
here's how you can do this,by using concurrency:
func ConcurrencyLoop(inputParameters *Profile) {
done := make(chan interface{})
var wg sync.WaitGroup
wg.Add(2)
servicesNameChan := TransformServiceNames(done, inputParameters.ServiceNames, &wg)
servicesInfoChan := TransformServiceInfo(done, inputParameters.Services, &wg)
if servicesName, ok := <-servicesNameChan; ok {
inputParameters.ServiceNames = servicesName
}
if servicesInfo, ok := <-servicesInfoChan; ok {
inputParameters.Services = servicesInfo
}
close(done)
wg.Wait()
}
func TransformServiceNames(done <-chan interface{}, servicesKey []ServiceKey, wg *sync.WaitGroup) <-chan []ServiceKey {
keysChan := make(chan []ServiceKey)
go func() {
defer wg.Done()
transformedServicekeys := make([]ServiceKey, 0)
for _, serviceKey := range servicesKey {
a := strings.Split(serviceKey.Service, "-")
s := a[len(a)-1]
transformedServicekeys = append(transformedServicekeys, ServiceKey{
Service: s,
})
}
for {
select {
case <-done:
return
case keysChan <- transformedServicekeys:
}
}
}()
return keysChan
}
func TransformServiceInfo(done <-chan interface{}, servicesKey []ServiceInfo, wg *sync.WaitGroup) <-chan []ServiceInfo {
keysChan := make(chan []ServiceInfo)
go func() {
defer wg.Done()
transformedServiceinfo := make([]ServiceInfo, 0)
for _, serviceKey := range servicesKey {
a := strings.Split(serviceKey.Service, "-")
s := a[len(a)-1]
transformedServiceinfo = append(transformedServiceinfo, ServiceInfo{
Service: s,
})
}
for {
select {
case <-done:
return
case keysChan <- transformedServiceinfo:
}
}
}()
return keysChan
}

Get Array of Nested JSON Struct in GO

I am new to GoLang, and have a question about filling an array from nested JSON data. I have looked through Stack overflow yesterday and cannot find this exact topic, only threads that are similar, but do not provide a direct solution.
Lets say I have some nested JSON data like what is given below:
How can I create a nested struct to fill an array of the close prices. My code is given below.
My goal is to have an array where, arr = {157.92, 142.19, 148.26}
Thanks in advance! I greatly appreciate any help!
{
"history": {
"day": [
{
"date": "2019-01-02",
"open": 154.89,
"high": 158.85,
"low": 154.23,
"close": 157.92,
"volume": 37039737
},
{
"date": "2019-01-03",
"open": 143.98,
"high": 145.72,
"low": 142.0,
"close": 142.19,
"volume": 91312195
},
{
"date": "2019-01-04",
"open": 144.53,
"high": 148.5499,
"low": 143.8,
"close": 148.26,
"volume": 58607070
}
...
]
}
}
// DATA STRUCTURE
type Hist struct {
History string `json:"history"`
}
type Date struct {
Day string `json:"day"`
}
type Price struct {
Close []string `json:"close"`
}
// HISTORICAL QUOTES
func get_quotes(arg1 string, arg2 string, arg3 string, arg4 string) []string {
// arg1 = ticker symbol, arg2 = start, arg3 = end, arg4 = access token
// TRADIER API
apiUrl := "https://sandbox.tradier.com/v1/markets/history?symbol=" + arg1 + "&interval=daily&start=" + arg2 + "&end=" + arg3
u, _ := url.ParseRequestURI(apiUrl)
urlStr := u.String()
client := &http.Client{}
r, _ := http.NewRequest("GET", urlStr, nil)
r.Header.Add("Authorization", "Bearer "+arg4)
r.Header.Add("Accept", "application/json")
resp, _ := client.Do(r)
responseData, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
fmt.Println(resp.Status)
fmt.Println(string(responseData))
var response Price
json.NewDecoder(resp.Body).Decode(&response)
fmt.Println(response.Close)
return response.Close
}
Something like this should give you what you need. Your data structure does not correctly reflect the response from the API. I used this tool to quickly convert the JSON value into a Go struct type. Once you're decoding the response correctly, then it's just a matter of iterating over each Day struct and appending the close value to an output array.
I added the core stuff for decoding and mapping the values. You can handle customizing the client, request, and headers however you'd like by combining what you've already got.
package main
import (
"encoding/json"
"fmt"
"log"
"net/http"
)
type Response struct {
History History `json:"history"`
}
type Day struct {
Date string `json:"date"`
Open float64 `json:"open"`
High float64 `json:"high"`
Low float64 `json:"low"`
Close float64 `json:"close"`
Volume int `json:"volume"`
}
type History struct {
Day []Day `json:"day"`
}
func main() {
prices, err := closePrices()
if err != nil {
log.Fatal(err)
}
fmt.Println(prices)
}
func closePrices() (out []float64, err error) {
resp, err := http.Get("...")
if err != nil {
return
}
r := Response{}
err = json.NewDecoder(resp.Body).Decode(&r)
if err != nil {
return
}
for _, d := range r.History.Day {
out = append(out, d.Close)
}
return
}

Build and write Json object of objects to file

I'm trying to take an array of strings that I receive from a Go API, and write them to a file in a weird json list format. There are not brackets [], so i have to create a "dimension" for each of the string values in the array. I'm trying to do this using types/structs, but i keep getting stuck (new at Go). Should i try and just use maps, or is there a way to accomplish this?
This is the code I am using right now:
package main
import (
"fmt"
"io/ioutil"
)
type Dimension struct {
SQL, Type string
}
type Measure struct {
Type string
DrillMembers []string
}
func check(e error) {
if e != nil {
panic(e)
}
}
func main() {
a := []string{"country", "year", "gdpPercap", "lifeExp", "pop", "continent"}
cubeSchema := "measures: {\n count: {\n type: `count`,\n drillMembers: "
for i, s := range a {
cubeSchema += s
fmt.Println(cubeSchema)
fmt.Println(i)
}
fileText := []byte(cubeSchema)
fmt.Println(cubeSchema)
err := ioutil.WriteFile("test.js", fileText, 0644)
check(err)
}
This is how I need the output to look:
measures: {
count: {
type: `count`,
drillMembers: [country]
}
},
dimensions: {
country: {
sql: `country`,
type: `string`
},
year: {
sql: `year`,
type: `string`
},
gdppercap: {
sql: `gdppercap`,
type: `string`
},
lifeexp: {
sql: `lifeexp`,
type: `string`
},
pop: {
sql: `pop`,
type: `string`
},
continent: {
sql: `continent`,
type: `string`
}
}
Right now I keep getting stuck with the following output:
measures: {
count: {
type: `count`,
drillMembers: countryyeargdpPercaplifeExppopcontinent
package main
import (
"fmt"
"io/ioutil"
)
func check(e error) {
if e != nil {
panic(e)
}
}
func main() {
schema := `measures: {
count: {
type: 'count',
drillMembers: [country]
}
},
dimensions: {
`
a := []string{"country", "year", "gdpPercap", "lifeExp", "pop", "continent"}
var cubeSchema string
for _, s := range a {
cubeSchema += s + ": {\n\tsql: " + s + ",\n\ttype: `string`\n},\n"
}
fileText := []byte(schema + cubeSchema + "}\n}")
fmt.Println(cubeSchema)
err := ioutil.WriteFile("test.js", fileText, 0644)
check(err)
}
check this code.
I tried to do the second part:
package main
import (
"encoding/json"
"fmt"
)
func main() {
a := []string{"country", "year", "gdpPercap", "lifeExp", "pop", "continent"}
var items map[string]sqlType
items = make(map[string]sqlType)
for _, v := range a {
items[v] = sqlType{SQL: v, Type: "string"}
}
dimensions := dimensions{Dimensions: items}
bytes, err := json.Marshal(dimensions)
if err != nil {
panic(err)
}
c := string(bytes)
fmt.Println(c)
}
type sqlType struct {
SQL string `json:"sql"`
Type string `json:"type"`
}
type dimensions struct {
Dimensions map[string]sqlType `json:"dimensions"`
}

How to parse the json array of the format below

{
"machines": [{
"name": "relay_1",
"totalmem": "3G",
"machinemem": "6G"
}, {
"name": "relay_2",
"totalmem": "30G",
"machinemem": "4G"
}]
}
tried doing the parsing using the below code
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("relay called")
conf, _ = rootCmd.Flags().GetString("conf")
if conf != "" {
fmt.Println("From Create Command : ", conf)
}
data, err := ioutil.ReadFile("file.txt") // data has type []byte
if err != nil {
log.Fatal(err)
}
var result []map[string]interface{}
json.Unmarshal(data, &result)
relays := result["relays"].(map[string]interface{})
for key, relay := range relays {
fmt.Println("name :", relay["name"],
"totalmem:", relay["totalmem"],
"relaymem:", relay["relaymem"])
}
},
But I am getting the error as below which indicates that the type is invalid
cmd/create_relay.go:54:29: invalid type assertion: result["relays"].(map[string]) (non-interface type map[string]interface {} on left)
Can someone let me know how to parse the json below by using the interfaces as below
It worked with the below code.
type Relays struct {
Relays []Relay `json:"relays"`
}
type Relay struct {
Name string `json:"name"`
Totalmem string `json:"totalmem"`
Relaymem string `json:"relaymem"`
}
// relayCmd represents the relay command
var createrelayCmd = &cobra.Command{
Use: "relay",
Short: "A brief description of your command",
Long: `A longer description that spans multiple lines and likely contains examples
and usage of using your command. For example:
Cobra is a CLI library for Go that empowers applications.
This application is a tool to generate the needed files
to quickly create a Cobra application.`,
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("relay called")
conf, _ = rootCmd.Flags().GetString("conf")
if conf != "" {
fmt.Println("From Create Command : ", conf)
jsonFile, err := os.Open(conf)
// if we os.Open returns an error then handle it
if err != nil {
fmt.Println(err)
}
fmt.Println("Successfully Opened users.json")
// defer the closing of our jsonFile so that we can parse it later on
defer jsonFile.Close()
data, err := ioutil.ReadAll(jsonFile) // data has type []byte
if err != nil {
log.Fatal(err)
}
var relays Relays
json.Unmarshal(data,&relays)
for i := 0; i < len(relays.Relays); i++ {
fmt.Println("User Name: " + relays.Relays[i].Name)
fmt.Println("User Totalmem: " + relays.Relays[i].Totalmem)
fmt.Println("User Relaymem: " + relays.Relays[i].Relaymem)
}
}
},
}
result in your code is an array of map and you are using result["relays"] which is invalid.
Your code should be something like this:
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("relay called")
conf, _ = rootCmd.Flags().GetString("conf")
if conf != "" {
fmt.Println("From Create Command : ", conf)
}
data, err := ioutil.ReadFile("file.txt") // data has type []byte
if err != nil {
log.Fatal(err)
}
var result map[string]interface{}
json.Unmarshal(data, &result)
relays := result["relays"].([]interface{})
for _, relay := range relays {
relayM := relay.(map[string]interface{})
fmt.Println("name :", relayM["name"].(string),
"totalmem:", relayM["totalmem"].(string),
"relaymem:", relayM["relaymem"].(string))
}
},

Only last row is printing

this is my go function
func logInFirst(res http.ResponseWriter, req *http.Request) {
type Resp struct {
Result []map[string]interface{} `json:"Result,omitempty"`
Result1 []map[string]interface{} `json:"Result1,omitempty"`
Result2 []map[string]interface{} `json:"Result2,omitempty"`
Status string `json:"Status"`
}
type AxleUser struct {
ShopID string `json:"ShopID"`
VehicleType string `json:"VehicleType"`
}
var Response Resp
Response.Status = "failed"
Result := make(map[string]interface{})
Result1 := make(map[string]interface{})
Result2 := make(map[string]interface{})
//db, err := sql.Open("mysql", "root:chikkIbuddI57#tcp(127.0.0.1:3306)/b2b")
db, err := sql.Open("mysql", "awsgobumpr:gobumpr123#tcp(briaxpgbmpr.cx4twoxoumct.ap-southeast-1.rds.amazonaws.com)/b2b_optimization")
if err != nil {
panic(err.Error())
}
defer db.Close()
rnd := render.New()
b, err := ioutil.ReadAll(req.Body)
defer req.Body.Close()
if err != nil {
panic(err.Error())
}
// Unmarshal the request body
var msg AxleUser
err = json.Unmarshal(b, &msg)
if err != nil {
panic(err.Error())
}
//fmt.Println(msg)
// get shop id from emp table using mobile number and password
brandrows, branderr := db.Query("SELECT DISTINCT brand,model FROM admin_vehicle_table_new WHERE type=?", msg.VehicleType)
if branderr != nil {
panic(branderr.Error())
}
brandcolumns, branderr := brandrows.Columns()
if branderr != nil {
panic(branderr.Error())
}
brandcount := len(brandcolumns)
brandValues := make([]string, brandcount)
brandScanArgs := make([]interface{}, brandcount)
for i := range brandValues {
brandScanArgs[i] = &brandValues[i]
}
for brandrows.Next() {
branderr := brandrows.Scan(brandScanArgs...)
//fmt.Println(branderr)
if branderr != nil {
panic(branderr.Error())
}
for i, v := range brandValues {
Result[brandcolumns[i]] = v
}
Response.Result = append(Response.Result, Result)
}
servicerows, serviceerr := db.Query("SELECT DISTINCT b2b_service_type FROM b2b_service_type WHERE b2b_vehicle_type=? and b2b_flag=0 and b2b_shop_id=0 UNION SELECT b2b_service_type FROM b2b_service_type WHERE b2b_vehicle_type=? and b2b_flag=0 and b2b_shop_id=?", msg.VehicleType, msg.VehicleType, msg.ShopID)
if serviceerr != nil {
panic(serviceerr.Error())
}
servicecolumns, serviceerr := servicerows.Columns()
if serviceerr != nil {
panic(serviceerr.Error())
}
servicecount := len(servicecolumns)
serviceValues := make([]string, servicecount)
serviceScanArgs := make([]interface{}, servicecount)
for i := range serviceValues {
serviceScanArgs[i] = &serviceValues[i]
}
for servicerows.Next() {
serviceerr := servicerows.Scan(serviceScanArgs...)
if serviceerr != nil {
panic(serviceerr.Error())
}
for i, v := range serviceValues {
Result1[servicecolumns[i]] = v
}
Response.Result1 = append(Response.Result1, Result1)
}
repairrows, repairerr := db.Query("SELECT DISTINCT b2b_repair_decription FROM b2b_repair_decription WHERE b2b_vehicle_type=? and b2b_shop_id=0 UNION SELECT b2b_repair_decription FROM b2b_repair_decription WHERE b2b_vehicle_type=? and b2b_shop_id=?", msg.VehicleType, msg.VehicleType, msg.ShopID)
if repairerr != nil {
panic(repairerr.Error())
}
repaircolumns, repairerr := repairrows.Columns()
if repairerr != nil {
panic(repairerr.Error())
}
repaircount := len(repaircolumns)
repairValues := make([]string, repaircount)
repairScanArgs := make([]interface{}, repaircount)
for i := range repairValues {
repairScanArgs[i] = &repairValues[i]
}
for repairrows.Next() {
repairerr := repairrows.Scan(repairScanArgs...)
if repairerr != nil {
panic(repairerr.Error())
}
for i, v := range repairValues {
Result2[repaircolumns[i]] = v
}
Response.Result2 = append(Response.Result2, Result2)
}
Response.Status = "success"
res.Header().Set("Content-Type", "application/json")
rnd.JSON(res, http.StatusOK, Response)
}
My Desrired output is a json string like this
{
"Result": [
{
"brand": "Hero Honda",
"model": "Passion Pro"
},
{
"brand": "Yamaha",
"model": "120"
},...
]
"Result1":[
{
"service_type" : "repairs",
},
{
"service_type" : "general service",
},...
]
"Result2":[
{
"b2b_repair_decription": "Tire Replacement"
},
{
"b2b_repair_decription": "Electric work"
},...
]
}
but the output which i got contains the same row instead of all the rows like
this,
{
"Result": [
{
"brand": "Yamaha",
"model": "120"
},
{
"brand": "Yamaha",
"model": "120"
},...
]
"Result1":[
{
"service_type" : "general service",
},
{
"service_type" : "general service",
},...
]
"Result2":[
{
"b2b_repair_decription": "Electric work"
},
{
"b2b_repair_decription": "Electric work"
},...
]
}
i tried appending in the loop , but it dint work. i even tried defining the Result, Result1, Result2 as array of interfaces
can someone help me with this issue?

Resources