Home >Backend Development >Golang >How to Unmarshal a Self-Referential JSON String in Go with a Dynamic Type?

How to Unmarshal a Self-Referential JSON String in Go with a Dynamic Type?

Mary-Kate Olsen
Mary-Kate OlsenOriginal
2024-12-25 13:13:09142browse

How to Unmarshal a Self-Referential JSON String in Go with a Dynamic Type?

Unmarshalling JSON String to a Struct with a Self-Referential Element

In Go, unmarshalling a JSON string to a struct with a self-referential element can be challenging. Let's explore a specific example and a solution to address this issue effectively.

JSON Input and Struct Definition

Consider the following JSON input:

[{
    "db": {
        "url": "mongodb://localhost",
        "port": "27000",
        "uname": "",
        "pass": "",
        "authdb": "",
        "replicas": [
            {
                "rs01": {
                    "url":"mongodb://localhost",
                    "port": "27001",
                    "uname": "",
                    "pass": "",
                    "authdb": ""
                }
            },
            {
                "rs02": {
                    "url":"mongodb://localhost",
                    "port": "27002",
                    "uname": "",
                    "pass": "",
                    "authdb": ""
                }
            }
        ]
    }
}]

And the corresponding Go struct:

type DBS struct {
    URL      string   `json:"url"`
    Port     string   `json:"port"`
    Uname    string   `json:"uname"`
    Pass     string   `json:"pass"`
    Authdb   string   `json:"authdb"`
    Replicas []DBS     `json:"replicas"`
}

Unmarshal Function and Output

The provided function, loadConfigs(), attempts to unmarshal the JSON string into a slice of DBS structs:

func loadConfigs() []DBS {
    var config []DBS
    raw, err := ioutil.ReadFile("./config.json")
    if err != nil {
        fmt.Println(err.Error())
        os.Exit(1)
    }

    json.Unmarshal(raw, &config)
    return config
}

However, this results in an empty slice, []DBS{, because the JSON input is not a slice of DBS structs but a JSON object wrapper containing an array of objects.

Solution: Mapping to a Dynamic Type

To fully describe the JSON input, a dynamic type like a map is required. The updated type definition becomes:

type DBSReplicated struct {
    DB *DBS `json:"db"`
}
type DBS struct {
    URL      string            `json:"url"`
    Port     string            `json:"port"`
    Uname    string            `json:"uname"`
    Pass     string            `json:"pass"`
    Authdb   string            `json:"authdb"`
    Replicas []map[string]*DBS `json:"replicas"`
}

Using this new type, we can parse the JSON input accurately:

var dbs []*DBReplicated
if err := json.Unmarshal([]byte(src), &dbs); err != nil {
    panic(err)
}

db := dbs[0].DB
fmt.Printf("%+v\n", db)
for _, dbs := range db.Replicas {
    for name, replica := range dbs {
        fmt.Printf("%s: %+v\n", name, replica)
    }
}

Output

&{URL:mongodb://localhost Port:27000 Uname: Pass: Authdb: Replicas:[map[rs01:0x10538200] map[rs02:0x10538240]]}
rs01: &{URL:mongodb://localhost Port:27001 Uname: Pass: Authdb: Replicas:[]}
rs02: &{URL:mongodb://localhost Port:27002 Uname: Pass: Authdb: Replicas:[]}

Key Points

  • Use a map type to model dynamic JSON input.
  • Pay attention to the proper syntax for JSON tag property names.
  • Consider using pointers in the struct to allow for nested structs.

The above is the detailed content of How to Unmarshal a Self-Referential JSON String in Go with a Dynamic Type?. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn