Goのインスタンスはjsonのmapとstructが変換を処理するのに便利であることを示している.

5577 ワード

今日はJSONデータ処理について簡単にお話しします.最近の仕事では、データベースデータをリアルタイムでelasticsearchに更新するため、実践の過程でJSONデータ処理の問題に遭遇しました.
リアルタイムデータ
リアルタイムデータ取得は、アリオープンソースのcanalコンポーネントによって実現され、メッセージキューkafkaを介してプロセッサに伝送される.我々が受信したJSONデータは以下のような形式である.
{
    "type": "UPDATE",
    "database": "blog",
    "table": "blog",
    "data": [
        {
            "blogId": "100001",
            "title": "title",
            "content": "this is a blog",
            "uid": "1000012",
            "state": "1"
        }
    ]
}

簡単にデータの論理を言えば、typeはデータベースイベントが新規、更新、または削除イベントであることを示し、databaseは対応するデータベース名を表し、tableは対応するテーブル名を表し、dataはデータベース内のデータである.
このJSONはどうやって処理しますか?
jsonがmapに変換
最初に思いついたのはjsonです.UnmarshalはJSONをmap[string]interface{}に変換します.
サンプルコード:
func main () {
    msg := []byte(`{
    "type": "UPDATE",
    "database": "blog",
    "table": "blog",
    "data": [
        {
            "blogId": "100001",
            "title": "title",
            "content": "this is a blog",
            "uid": "1000012",
            "state": "1"
        }
    ]}`)
    var event map[string]interface{}
    if err := json.Unmarshal(msg, &event); err != nil {
        panic(err)
    }

    fmt.Println(event)
}

印刷結果は次のとおりです.
map[data:[map[title:title content:this is a blog uid:1000012 state:1 blogId:100001]] type:UPDATE database:blog table:blog]

これで,データの解析に成功した.次はそれを使いますが、mapには通常いくつかの不足があると思います.
  • keyによってデータを取得すると、存在しないkeyが現れる可能性があり、厳格さのためにkeyが存在するかどうかを検査する必要がある.
  • 構造体に対する方式では、mapデータの抽出が不便でIDE補完検査が利用できず、keyが書き間違えやすい.

  • この場合、どのように対応すればよいでしょうか.JSONをstructに変換できれば良いのですが.
    jsonをstructに変換
    GOでは、jsonがstructに変換するのも便利で、変換したstructを事前に定義するだけでよい.まず変換structを定義します.
    type Event struct {
        Type     string              `json:"type"`
        Database string              `json:"database"`
        Table    string              `json:"table"`
        Data     []map[string]string `json:"data"`
    }

    何時に説明しますか.
  • 実際のシーンでは、canalメッセージのdata構造はテーブルによって決定され、JSONが解析に成功するまで事前に知ることができないため、ここではmap[string]stringと定義する.
  • 変換された構造体メンバーはエクスポート可能でなければならないので、メンバー変数名はすべて大文字であり、JSONとのマッピングはjson:"tagName"のtagNameによって完了する.

  • 解析コードは、次のように簡単です.
    e := Event{}
    if err := json.Unmarshal(msg, &e); err != nil {
        panic(err)
    }
    
    fmt.Println(e)

    印刷結果:
    {UPDATE blog blog [map[blogId:100001 title:title content:this is a blog uid:1000012 state:1]]}

    次に、イベントタイプ取得、event.Typeで完了します.しかし、dataはまだ[]map[string]stringタイプなので、mapの問題は依然としてあります.
    mapをstructに変換できますか?
    mapをstructに変換
    私の知る限りmapはstructに変換され、GOは内蔵されていません.実現するにはGOの反射機構に依存する必要がある.
    しかし、幸いなことに、実はすでにこのことをした人がいて、バッグの名前はmapstructureで、使用もとても簡単で、それが提供したいくつかの例を叩いてマスターしました.READMEでも、このライブラリは主にJSONの一部を読み込まなければ残りのデータ構造を知ることができないシーンに遭遇し、私のシーンとこのように一致していると述べています.
    インストールコマンドは次のとおりです.
    $ go get https://github.com/mitchellh/mapstructure

    使用を開始する前に、mapが変換するstruct構造、すなわちblog構造体を定義します.以下のようにします.
    type Blog struct {
        BlogId  string `mapstructure:"blogId"`
        Title   string `mapstructrue:"title"`
        Content string `mapstructure:"content"`
        Uid     string `mapstructure:"uid"`
        State   string `mapstructure:"state"`
    }

    なぜなら、次に使用するのはmapstructureパッケージなので、struct tag識別はjsonではなくmapstructureです.
    サンプルコードは次のとおりです.
    e := Event{}
    if err := json.Unmarshal(msg, &e); err != nil {
        panic(err)
    }
    
    if e.Table == "blog" {
        var blogs []Blog
    
        if err := mapstructure.Decode(e.Data, &blogs); err != nil {
            panic(err)
        }
    
        fmt.Println(blogs)
    }

    eventの解析は前述と同様に,e.Tableによりblogテーブルからのデータであるか否かを判断し,もしそうであればBlog構造体を用いて解析する.次にmapstructureのDecodeで解析を完了する.
    印刷結果は次のとおりです.
    [{100001 title this is a blog 1000012 1}]

    これで、すべての仕事が終わったようです.いや!
    弱型解析
    Blog構造体のすべてのメンバーがstringであり、canalが行うべきことであり、すべての値タイプがstringであるという問題を発見したかどうか分かりません.しかし、実際にはblogテーブルのuidフィールドとstateフィールドはintです.
    理想的な構造体定義は以下のようにすべきである.
    type Blog struct {
        BlogId  string `mapstructure:"blogId"`
        Title   string `mapstructrue:"title"`
        Content string `mapstructure:"content"`
        Uid     int32  `mapstructure:"uid"`
        State   int32  `mapstructure:"state"`
    }

    しかし、新しいBlogタイプを前のコードに代入すると、次のようなエラーが発生します.
    panic: 2 error(s) decoding:
    
    * '[0].state' expected type 'int32', got unconvertible type 'string'
    * '[0].uid' expected type 'int32', got unconvertible type 'string'

    プロンプトタイプの解析に失敗しました.実は、このような形式のjsonは他のいくつかのソフトタイプの言語にも現れます.
    どうやってこの問題を解決しますか?2つのソリューションを提案
  • は、int型のデータなどの使用時に変換する、strconvを使用することができる.Atoi変換.
  • mapstructureが提供するソフトタイプmap変換structの機能を使用する.

  • 明らかに、最初の方法はlowすぎて、変換する時にもっと多くのエラーチェックが必要です.2つ目の方法はどうですか?
    サンプルコードを見ると、次のようになります.
    var blogs []Blog
    if err := mapstructure.WeakDecode(e.Data, &blogs); err != nil {
        panic(err)
    }
    
    fmt.Println(blogs)

    実はmapstructureのDecodeをWeakDecodeに置き換えるだけでいいのですが、字はその意味で、弱解析です.このようにeasy.
    これでやっと完成だ!次のデータ処理はずっと簡単です.mapstructureの使用を学びたいなら、ソースコードを叩く例は多くないはずです.