代码之家  ›  专栏  ›  技术社区  ›  MrDuk

为什么不能将这些数据正确地解组到我的对象模型中?

  •  0
  • MrDuk  · 技术社区  · 6 年前

    我这里有一个(非)工作示例: https://play.golang.org/p/qaYhKvJ65J3

    我不知道为什么会有以下数据:

    alertData := `{
        "Id": 0,
        "Version": 0,
        "OrgId": 1,
        "DashboardId": 61,
        "PanelId": 84,
        "Name": "{qa-dev}{stats-pipeline} Topology Message Age (aggregator) alert",
        "Message": "",
        "Severity": "",
        "State": "",
        "Handler": 1,
        "Silenced": false,
        "ExecutionError": "",
        "Frequency": 10,
        "EvalData": null,
        "NewStateDate": "0001-01-01T00:00:00Z",
        "PrevStateDate": "0001-01-01T00:00:00Z",
        "StateChanges": 0,
        "Created": "0001-01-01T00:00:00Z",
        "Updated": "0001-01-01T00:00:00Z",
        "Settings": {
            "conditions": [
                {
                    "evaluator": {
                        "params": [
                            10000
                        ],
                        "type": "gt"
                    },
                    "operator": {
                        "type": "and"
                    },
                    "query": {
                        "datasourceId": 2,
                        "model": {
                            "hide": true,
                            "refCount": 0,
                            "refId": "C",
                            "textEditor": false
                        },
                        "params": [
                            "C",
                            "5m",
                            "now"
                        ]
                    },
                    "reducer": {
                        "params": [],
                        "type": "avg"
                    },
                    "type": "query"
                }
            ],
            "executionErrorState": "keep_state",
            "frequency": "10s",
            "handler": 1,
            "name": "{qa-dev}{stats-pipeline} Topology Message Age (aggregator) alert",
            "noDataState": "keep_state",
            "notifications": []
        }
    }`
    

    无法解组到以下对象模型中:

    type Condition struct {
        Evaluator struct {
            Params []int  `json:"params"`
            Type   string `json:"type"`
        } `json:"evaluator"`
        Operator struct {
            Type string `json:"type"`
        } `json:"operator"`
        Query struct {
            Params []string `json:"params"`
        } `json:"query"`
        Reducer struct {
            Params []interface{} `json:"params"`
            Type   string        `json:"type"`
        } `json:"reducer"`
        Type string `json:"type"`
    }
    

    condition := Condition{}
    err := json.Unmarshal([]byte(alertData), &condition)
    
    if err != nil {
        panic(err)
    }
    
    fmt.Printf("\n\n json object:::: %+v", condition)
    

    我只是得到: json object:::: {Evaluator:{Params:[] Type:} Operator:{Type:} Query:{Params:[]} Reducer:{Params:[] Type:} Type:}

    理想情况下我可以把它解析成 type Conditions []struct{ } 但我不确定你是否能将模型定义为列表?

    2 回复  |  直到 6 年前
        1
  •  1
  •   maerics    6 年前

    看起来您正在尝试访问嵌套在根“Settings”属性下的“conditions”属性。因此,您需要定义根级别类型和足够的字段来告诉解组器如何查找目标属性。因此,您只需要创建一个新的“AlertData”类型,其中包含必要的“Settings/conditions”字段。

    例如( Go Playground

    type AlertData struct {
      Settings struct {
        Conditions []Condition `json:"conditions"`
      }
    }
    
    func main() {
      alert := AlertData{}
      err := json.Unmarshal([]byte(alertData), &alert)
    
      if err != nil {
        panic(err)
      }
    
      fmt.Printf("OK: conditions=%#v\n", alert.Settings.Conditions)
      // OK: conditions=[]main.Condition{main.Condition{Evaluator:struct { Params []int "json:\"params\""; Type string "json:\"type\"" }{Params:[]int{10000}, Type:"gt"}, Operator:struct { Type string "json:\"type\"" }{Type:"and"}, Query:struct { Params []string "json:\"params\"" }{Params:[]string{"C", "5m", "now"}}, Reducer:struct { Params []interface {} "json:\"params\""; Type string "json:\"type\"" }{Params:[]interface {}{}, Type:"avg"}, Type:"query"}}
    }
    

    请注意,打印的列表包含了太多类型信息,因为“Condition”类型使用匿名结构作为字段类型。如果要将它们提取到命名结构中,则使用数据会更容易,例如:

    type Condition struct {
      Evaluator Evaluator `json:"evaluator"`
      Operator  Operator  `json:"operator"`
      // ...
    }
    
    type Evaluator struct {
      Params []int  `json:"params"`
      Type   string `json:"type"`
    }
    
    type Operator struct {
      Type string `json:"type"`
    }
    
    //...
    // OK: conditions=[]main.Condition{
    //   main.Condition{
    //     Evaluator:main.Evaluator{Params:[]int{10000}, Type:"gt"},
    //     Operator:main.Operator{Type:"and"},
    //     Query:main.Query{Params:[]string{"C", "5m", "now"}},
    //     Reducer:main.Reducer{Params:[]interface {}{}, Type:"avg"},
    //     Type:"query",
    //   },
    // }
    

    Go Playground example here...

        2
  •  0
  •   reticentroot    6 年前

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

    package main
    
    import (
        "encoding/json"
        "fmt"
        "log"
        "time"
    )
    
    type Data struct {
        ID             int         `json:"Id"`
        Version        int         `json:"Version"`
        OrgID          int         `json:"OrgId"`
        DashboardID    int         `json:"DashboardId"`
        PanelID        int         `json:"PanelId"`
        Name           string      `json:"Name"`
        Message        string      `json:"Message"`
        Severity       string      `json:"Severity"`
        State          string      `json:"State"`
        Handler        int         `json:"Handler"`
        Silenced       bool        `json:"Silenced"`
        ExecutionError string      `json:"ExecutionError"`
        Frequency      int         `json:"Frequency"`
        EvalData       interface{} `json:"EvalData"`
        NewStateDate   time.Time   `json:"NewStateDate"`
        PrevStateDate  time.Time   `json:"PrevStateDate"`
        StateChanges   int         `json:"StateChanges"`
        Created        time.Time   `json:"Created"`
        Updated        time.Time   `json:"Updated"`
        Settings       struct {
            Conditions          []Condition   `json:"conditions"`
            ExecutionErrorState string        `json:"executionErrorState"`
            Frequency           string        `json:"frequency"`
            Handler             int           `json:"handler"`
            Name                string        `json:"name"`
            NoDataState         string        `json:"noDataState"`
            Notifications       []interface{} `json:"notifications"`
        } `json:"Settings"`
    }
    
    type Condition struct {
        Evaluator struct {
            Params []int  `json:"params"`
            Type   string `json:"type"`
        } `json:"evaluator"`
        Operator struct {
            Type string `json:"type"`
        } `json:"operator"`
        Query struct {
            DatasourceID int `json:"datasourceId"`
            Model        struct {
                Hide       bool   `json:"hide"`
                RefCount   int    `json:"refCount"`
                RefID      string `json:"refId"`
                TextEditor bool   `json:"textEditor"`
            } `json:"model"`
            Params []string `json:"params"`
        } `json:"query"`
        Reducer struct {
            Params []interface{} `json:"params"`
            Type   string        `json:"type"`
        } `json:"reducer"`
        Type string `json:"type"`
    }
    
    func (d Data) GetFirstCondition() (Condition, error) {
        if len(d.Settings.Conditions) > 0 {
            return d.Settings.Conditions[0], nil
        }
        return Condition{}, fmt.Errorf("no conditions found")
    }
    
    func (d Data) GetConditionByIndex(index uint) (Condition, error) {
        if len(d.Settings.Conditions) == 0 {
            return Condition{}, fmt.Errorf("no conditions found")
        }
    
        if int(index) > len(d.Settings.Conditions)-1 {
            return Condition{}, fmt.Errorf("index out of bounds")
        }
    
        return d.Settings.Conditions[index], nil
    }
    
    var alertData = `{
        "Id": 0,
        "Version": 0,
        "OrgId": 1,
        "DashboardId": 61,
        "PanelId": 84,
        "Name": "{qa-dev}{stats-pipeline} Topology Message Age (aggregator) alert",
        "Message": "",
        "Severity": "",
        "State": "",
        "Handler": 1,
        "Silenced": false,
        "ExecutionError": "",
        "Frequency": 10,
        "EvalData": null,
        "NewStateDate": "0001-01-01T00:00:00Z",
        "PrevStateDate": "0001-01-01T00:00:00Z",
        "StateChanges": 0,
        "Created": "0001-01-01T00:00:00Z",
        "Updated": "0001-01-01T00:00:00Z",
        "Settings": {
            "conditions": [
                {
                    "evaluator": {
                        "params": [
                            10000
                        ],
                        "type": "gt"
                    },
                    "operator": {
                        "type": "and"
                    },
                    "query": {
                        "datasourceId": 2,
                        "model": {
                            "hide": true,
                            "refCount": 0,
                            "refId": "C",
                            "textEditor": false
                        },
                        "params": [
                            "C",
                            "5m",
                            "now"
                        ]
                    },
                    "reducer": {
                        "params": [],
                        "type": "avg"
                    },
                    "type": "query"
                }
            ],
            "executionErrorState": "keep_state",
            "frequency": "10s",
            "handler": 1,
            "name": "{qa-dev}{stats-pipeline} Topology Message Age (aggregator) alert",
            "noDataState": "keep_state",
            "notifications": []
        }
    }`
    
    func main() {
        var res Data
        err := json.Unmarshal([]byte(alertData), &res)
        if err != nil {
            log.Fatal(err)
        }
        fmt.Println(res.GetFirstCondition())
        fmt.Println(res.GetConditionByIndex(0))
        // should fail :-)
        fmt.Println(res.GetConditionByIndex(1))
    
    }