1

My issue is

  1. I want to be able to loop over each server and within that loop, loop over UsageData
  2. My current loop gives me an error about ranging over assets not sure why
  3. I cant access assets.Server.UsageData

Here is my code : https://go.dev/play/p/ttNVW5_Q4Ys

package main

import (
    "encoding/json"
    "fmt"
)

type Asset struct {
    Server struct {
        Host string `json:"host"`
        Port string `json:"port"`
    } `json:"server"`
    Postgres struct {
        Host      string `json:"host"`
        User      string `json:"user"`
        Password  string `json:"password"`
        DB        string `json:"db"`
        UsageData []struct {
            Region string `json:"Region"`
            Mbps   int    `json:"Mpbs"`
        } `json:"UsageData"`
    } `json:"database"`
}

func main() {
    jsonConfig := []byte(`[
    {
        "server":{
            "host":"serverA",
            "port":"8080"},
        "database":{
            "host":"serverA",
            "user":"db_user",
            "password":"supersecret",
            "db":"A_db",
            "UsageData":[{"Region":"US","Mbps":100}, {"Region":"EU","Mbps":140}]
        }
    },
    {
        "server":{
            "host":"serverB",
            "port":"8383"},
        "database":{
            "host":"serverB",
            "user":"db_user2",
            "password":"acbd123",
            "db":"B_db",
            "UsageData":[{"Region":"US","Mbps":58}, {"Region":"EU","Mbps":250}]
        }   
    }
]`)
    var assets []Asset
    err := json.Unmarshal(jsonConfig, &assets)
    if err != nil {
        panic(err)
    }
    fmt.Printf("Assets: %+v\n", assets)
    //fmt.Printf("Config: %+v\n", assets.Server.Host)
    //fmt.Printf("Config: %+v\n", assets.database.UsageData)
    //fmt.Printf("Config: %+v\n", assets.Server.UsageData)

    for _, asset := range assets {
        fmt.Printf("%v\n", asset)
        //for _, Usage := range assets.UsageData {
        //  fmt.Printf("%v\n",Usage)
        //}
    }
}

** Code with the correct answer, I was calling the nested struct incorrectly**

https://go.dev/play/p/tEbA405WWbC

chowpay
  • 1,515
  • 6
  • 22
  • 44
  • 1
    You can't loop over a struct's fields with plain Go, it's not supported by the language. You need to use reflection to be able to do that. You could unmarshal the json into a map which allows looping but that has other drawbacks when compared to struct. – mkopriva Mar 17 '22 at 08:00
  • I'm really confused on how to apply reflection. Here's where im stuck now go.dev/play/p/76te17MmJcI – chowpay Mar 17 '22 at 18:03
  • you don't need reflection if you are willing to access the fields directly, and to loop over `UserData` which is a slice you also don't need reflection, slices are meant to be iterated over, you just need to correct [selector](https://go.dev/ref/spec#Selectors) to access it: https://go.dev/play/p/cOhUvpUWQPZ – mkopriva Mar 17 '22 at 18:11

1 Answers1

2

Provided jsonConfig is not technically incorrect but keys SHOULD be unique (see question).
It seems that encoding/json will override value with last occurrence.

So you have 2 options:

  1. change jsonConfig to [{asset1}, {asset2}] (see fixed playground)
  2. implement custom unmarshaler

I definitely recommend first option.

medasx
  • 634
  • 4
  • 7
  • Ok I see what you did there with asset1, asset2, oversight on mypart. But how do you loop inside to get to the userData. For example : https://go.dev/play/p/76te17MmJcI – chowpay Mar 17 '22 at 17:59
  • 1
    @chowpay You're trying to access field from nested struct. Use `asset.Postgres.UsageData` – medasx Mar 17 '22 at 19:00