@kyanny's blog

自分の不名誉になるような考えを最初に大胆に表明することは、自立への第一歩となる - ニーチェ ドイツ哲学者

Go で PostgreSQL の JSON/JSONB データ型を扱う

PostgreSQL 側で JSON/JSONB 型としてフィールドが定義されていれば、 Go プログラムからは string なり []byte なりを INSERT するだけで良い。

dataString := `{"a":"A","b":"B"}`
_, err = db.Exec("insert into t (dataType, json, jsonb) values($1, $2, $3)", "string", dataString, dataString)

dataBytes := []byte(`{"a":"A","b":"B"}`)
_, err = db.Exec("insert into t (dataType, json, jsonb) values($1, $2, $3)", "[]byte", dataBytes, dataBytes)

SELECT するとき rows.Scan() に渡す型に応じて string なり []byte なりで取得できる。

rows, err := db.Query("select dataType, json, jsonb from t")
for rows.Next() {
    var dataType string
    var json string
    var jsonb string
    rows.Scan(&dataType, &json, &jsonb)
    fmt.Printf("%s %#v %#v\n", dataType, json, jsonb)
}

rows, err = db.Query("select dataType, json, jsonb from t")
for rows.Next() {
    var dataType string
    var json []byte
    var jsonb []byte
    rows.Scan(&dataType, &json, &jsonb)
    fmt.Printf("%s %#v %#v\n", dataType, json, jsonb)
}

Full code snippet (PostgreSQL サーバを起動しておく必要あり)

https://play.golang.org/p/ViHTxu7poOp

string "{\"a\":\"A\",\"b\":\"B\"}" "{\"a\": \"A\", \"b\": \"B\"}"
[]byte "{\"a\":\"A\",\"b\":\"B\"}" "{\"a\": \"A\", \"b\": \"B\"}"
string []byte{0x7b, 0x22, 0x61, 0x22, 0x3a, 0x22, 0x41, 0x22, 0x2c, 0x22, 0x62, 0x22, 0x3a, 0x22, 0x42, 0x22, 0x7d} []byte{0x7b, 0x22, 0x61, 0x22, 0x3a, 0x20, 0x22, 0x41, 0x22, 0x2c, 0x20, 0x22, 0x62, 0x22, 0x3a, 0x20, 0x22, 0x42, 0x22, 0x7d}
[]byte []byte{0x7b, 0x22, 0x61, 0x22, 0x3a, 0x22, 0x41, 0x22, 0x2c, 0x22, 0x62, 0x22, 0x3a, 0x22, 0x42, 0x22, 0x7d} []byte{0x7b, 0x22, 0x61, 0x22, 0x3a, 0x20, 0x22, 0x41, 0x22, 0x2c, 0x20, 0x22, 0x62, 0x22, 0x3a, 0x20, 0x22, 0x42, 0x22, 0x7d}

ちゃんと JSON/JSONB 型として保存されているので、 JSON 演算子が使える。

postgres=# select json->'a', jsonb->'b' from t;
 ?column? | ?column?
----------+----------
 "A"      | "B"
 "A"      | "B"
(2 rows)