Home > Software engineering >  How to get values from list nested within list in JSON
How to get values from list nested within list in JSON

Time:10-07

I have a JSON structure such as:

    {
       "persons":[
          {
             "name":"mark",
             "surname":"zuckerberg",
             "data":[
                {
                   "userid":"09210",
                   "username":"mark290",
                   "registered_date":"10-01-2017"
                },

                {
                   "userid":"092240",
                   "username":"mark291",
                   "registered_date":"11-01-2017"
                }
             ]
          },

          {
             "name":"bill",
             "surname":"clinton",
             "data":[
                {
                   "userid":"0442340",
                   "username":"billy",
                   "registered_date":"10-01-2000"
                },

                {
                   "userid":"89472894",
                   "username":"billary",
                   "registered_date":"11-01-2015"
                }
             ]
          }
       ]
    }

I need to fetch each username for each person. Currently, in Go, which I am a total newbie at, I can get only the single JSONS within "data", with this snippet:

    j := []byte(data)
    var f interface{}
    err := json.Unmarshal(j, &f)
    map := f.(map[string]interface{})
    for _,item := range map["persons"].([]interface{}) {
        fmt.Printf("%v", item.(map[string]interface{})["data"])
    fmt.Println(err)

I struggle to understand how to dive within each JSON struct within data in order to get each key,value pair.

CodePudding user response:

You can define the accurate nested structure corresponding to the JSON bytes, to Unmarshal.

package main

import (
    "encoding/json"
    "fmt"
)

type Trunk struct {
    Persons []Person `json:"persons"`
}

type Person struct {
    Name    string `json:"name"`
    Surname string `json:"surname"`
    Data    []User `json:"data"`
}

type User struct {
    Userid          string `json:"userid"`
    Username        string `json:"username"`
    Registered_date string `json:"registered_date"`
}

func main() {
    rawstring := []byte(`
    {
       "persons":[
          {
             "name":"mark",
             "surname":"zuckerberg",
             "data":[
                {
                   "userid":"09210",
                   "username":"mark290",
                   "registered_date":"10-01-2017"
                },

                {
                   "userid":"092240",
                   "username":"mark291",
                   "registered_date":"11-01-2017"
                }
             ]
          },

          {
             "name":"bill",
             "surname":"clinton",
             "data":[
                {
                   "userid":"0442340",
                   "username":"billy",
                   "registered_date":"10-01-2000"
                },

                {
                   "userid":"89472894",
                   "username":"billary",
                   "registered_date":"11-01-2015"
                }
             ]
          }
       ]
    }
    `)

    jsondata := Trunk{}
    if err := json.Unmarshal(rawstring, &jsondata); err == nil {
        fmt.Println(jsondata)

        // print first username of first person
        // fmt.Println(jsondata.Persons[0].Data[0].Username)
        // print each username of each person
        for _, person := range jsondata.Persons {
            for _, d := range person.Data {
                fmt.Println(d.Username)
            }
        }
    } else {
        fmt.Println("Unmarshal failed!")
    }
}

Or use a more compact structure defination:

type Trunk struct {
    Persons []struct {
        Name    string `json:"name"`
        Surname string `json:"surname"`
        Data    []struct {
            Userid          string `json:"userid"`
            Username        string `json:"username"`
            Registered_date string `json:"registered_date"`
        } `json:"data"`
    } `json:"persons"`
}

CodePudding user response:

If you want to use streaming approach you can try to Decoder to find "username" Token and get next Token with "value".

dec := json.NewDecoder(strings.NewReader(rawstring))
for {
    t, err := dec.Token()
    if err == io.EOF {
        break
    }
    if err != nil {
        log.Fatal(err)
    }
    if val, ok := t.(string); ok && val == "username" {
        t, err := dec.Token()
        if err == io.EOF {
            break
        }
        fmt.Println(t)
    }
}

PLAYGROUND

  • Related