如何提取嵌套的JSON数据?

I have the following in data.json:

{  
    "table":"orderBook10",
    "action":"update",
    "data":[  
       {  
          "symbol":"XBTUSD",
          "bids":[  
             [  
                3996,
                49137
             ],
             [  
                3995.5,
                116
             ],
             [  
                3995,
                165
             ],
             [  
                3994.5,
                166
             ],
             [  
                3994,
                237
             ],
             [  
                3993.5,
                45
             ],
             [  
                3992,
                20064
             ],
             [  
                3991.5,
                209
             ],
             [  
                3991,
                134
             ],
             [  
                3990.5,
                2948
             ]
          ],
          "timestamp":"2019-03-23T00:34:40.505Z",
          "asks":[  
             [  
                3996.5,
                975
             ],
             [  
                3997,
                289
             ],
             [  
                3997.5,
                334
             ],
             [  
                3998,
                419
             ],
             [  
                3998.5,
                423
             ],
             [  
                3999,
                930
             ],
             [  
                3999.5,
                547
             ],
             [  
                4000,
                538
             ],
             [  
                4000.5,
                703
             ],
             [  
                4001,
                997
             ]
          ]
       }
    ]
 }

My program can so far extract the data field:

package main

import (
    "encoding/json"
    "fmt"
    "io/ioutil"
)

func main() {

    dat, err := ioutil.ReadFile("./data.json")
    if err != nil {
        panic(err)
    }

    var ob map[string]interface{}
    if err := json.Unmarshal(dat, &ob); err != nil {
        panic(err)
    }
    fmt.Println(ob["data"])
}

I would now like to extract the nested "asks" field.

I've tried:

data := ob["data"]
asks := data["asks"].([][]int)

but this results in a syntax error that I can't decipher.

How do I assign the nested asks field to a variable?

Your ob["data"] JSON structure is as follows:

([]interface {}) {
  (map[string]interface {}) {
    (string) "": (string) "",
    (string) "": ([]interface {}) {
      ([]interface {}) {
        (float64),
        (float64) 
      }
    },
    (string) "": (string) "",
    (string) "": ([]interface {}) {
      ([]interface {}) {
        (float64),
        (float64)
      }
    }
  }
}

so you would need to use the following:

ob["data"].([]interface{})[0].(map[string]interface{})["asks"]

which:

  • casts ob["data"] to []interface{}
  • use the first (and in your example, the only) element [0]
  • cast this element to map[string]interface{}, and
  • then extract "asks"

Note: Unless you are sure, always use this form t, ok := i.(T) for type assertions:

If i holds a T, then t will be the underlying value and ok will be true.

If not, ok will be false and t will be the zero value of type T, and no panic occurs.

The approach to parse any JSON can be achieved by the following.

Step 1: Define the Structures

type OuterJson struct {
  Table string `json:"table"`
  Action string `json:"action"`
  DataJson []DataJson `json:"data"`
}

type DataJson struct {
  Symbol string `json:"symbol"`
  Timestamp string `json:"timestamp"`
  BidsJson [][]float64 `json:"bids"`
  AsksJson [][]float64 `json:"asks"`

}

Step 2: Declare the input and output

input := `{"table":"orderBook10","action":"update","data":[{"symbol":"XBTUSD","bids":[[3996,49137],[3995.5,116],[3995,165],[3994.5,166],[3994,237],[3993.5,45],[3992,20064],[3991.5,209],[3991,134],[3990.5,2948]],"timestamp":"2019-03-23T00:34:40.505Z","asks":[[3996.5,975],[3997,289],[3997.5,334],[3998,419],[3998.5,423],[3999,930],[3999.5,547],[4000,538],[4000.5,703],[4001,997]]}]}`
var output OuterJson

Step 3: Obtain the output from the given input (or Unmarshalling)

json.Unmarshal([]byte(input), &output)

Combining all, you get

package main

import (
    "fmt"
    "encoding/json"
)

type OuterJson struct {
  Table string `json:"table"`
  Action string `json:"action"`
  DataJson []DataJson `json:"data"`
}

type DataJson struct {
  Symbol string `json:"symbol"`
  Timestamp string `json:"timestamp"`
  BidsJson [][]float64 `json:"bids"`
  AsksJson [][]float64 `json:"asks"`

}  

func main() {
    fmt.Println("Hello, playground")
    input := `{"table":"orderBook10","action":"update","data":[{"symbol":"XBTUSD","bids":[[3996,49137],[3995.5,116],[3995,165],[3994.5,166],[3994,237],[3993.5,45],[3992,20064],[3991.5,209],[3991,134],[3990.5,2948]],"timestamp":"2019-03-23T00:34:40.505Z","asks":[[3996.5,975],[3997,289],[3997.5,334],[3998,419],[3998.5,423],[3999,930],[3999.5,547],[4000,538],[4000.5,703],[4001,997]]}]}`
    var output OuterJson
    json.Unmarshal([]byte(input), &output)
    fmt.Println(output)     
}

Try this link

You Struct structure should be

package main

import (
    "encoding/json"
    "fmt"
    "io/ioutil"
)
type JsonData struct {
    Table  string `json:"table"`
    Action string `json:"action"`
    Data   []struct {
        Symbol    string      `json:"symbol"`
        Bids      [][]int     `json:"bids"`
        Timestamp time.Time   `json:"timestamp"`
        Asks      [][]float64 `json:"asks"`
    } `json:"data"`
}

func main() {
    dat, err := ioutil.ReadFile("./data.json")
    if err != nil {
        panic(err)
    }

    var ob JsonData
    if err := json.Unmarshal([]byte(dat), &ob); err != nil {
        panic(err)
    }
    fmt.Println(ob)
   }

You can make use of below links for generating struct from nested JSON objects.

https://mholt.github.io/json-to-go/

http://json2struct.mervine.net/