post Image
GolangでPostgreSQLのJSONデータ型を読み書きする

tl;dr

結論から言うと全然難しくないです。
読み込む時はjsonのキーを指定してintやstringで読み込むか、jsonを丸ごと取得して構造体にunmarshalします。
書き込むときも構造体をmarshalしてSQLに渡すだけです。

テーブルの用意

ユーザ、データベースの作成は割愛します。

$ psql -U test_user test_db
test_db=> CREATE TABLE jojo ( id serial, chapter int, data json );

INSERT INTO jojo VALUES (1, '{ "title": "ファントムブラッド", "character": { "hero": "ジョナサン・ジョースター" } }');
INSERT INTO jojo VALUES (2, '{ "title": "戦闘潮流", "character": { "hero": "ジョセフ・ジョースター" } }');
INSERT INTO jojo VALUES (3, '{ "title": "スターダストクルセイダース", "character": { "hero": "空条承太郎" } }');

このとき、heroのフィールドを指定してSELECTするには以下のようにします。

test_db=> SELECT data->'character'->>'hero' AS hero FROM jojo;
           hero
--------------------------
 ジョナサン・ジョースター
 ジョセフ・ジョースター
 空条承太郎
(3 rows)

GolangでPostgreSQLのJSONデータを扱う

とりあえずデータを読んでみる

PostgreSQL用のドライバが必要なので取得します。

$ go get github.com/lib/pq

JSONのことは意識せず、直接SELECTしてみます。

postgersql.go
package main

import (
    "database/sql"
    "fmt"
    _ "github.com/lib/pq" // 読み込むだけで直接は使わない
)
func main() {
    db, _ := sql.Open("postgres", "user=test_user password=password dbname=test_db sslmode=disable")
    defer db.Close()

    // SELECT(JSONのフィールドを直接指定)
    rows, _ := db.Query("SELECT data->'character'->>'hero' as hero FROM jojo;")

    //ポインタが先頭より前なので1つ目でも`Next()`が必要
    for rows.Next() {
        var hero string // 普通にstringとして読める
        rows.Scan(&hero)
        fmt.Println(hero)
    }
}

->->>を使ってフィールドを直接読み込めばJSONであることは特に意識しなくても読み出すことができます。

$ go run postgresql.go

> ジョナサン・ジョースター
> ジョセフ・ジョースター
> 空条承太郎

JSONのデータを読み書きする

さて、本題です。テーブルのスキーマ状態に合わせて構造体を作り、json.Marshal()json.Unmarshal()を使ってデータを扱います。

postgresql.go
package main

import (
    "database/sql"
    "encoding/json"
    "fmt"
    "github.com/k0kubun/pp" //見やすさのために利用させていただいてます
    _ "github.com/lib/pq"
)

type Jojo struct {
    ID       int64
    Chapter  int
    JojoData json.RawMessage
}

type JojoData struct {
    Title     string    `json:"title"`
    Character Character `json:"character"`
}

type Character struct {
    Hero string `json:"hero"`
}

func main() {
    db, _ := sql.Open("postgres", "user=test_user password=password dbname=test_db sslmode=disable")
    defer db.Close()

    // INSERT
    insertQuery := "insert into jojo (chapter, data) values($1, $2)"

    // 構造体としてデータを作成します
    newCharacter := Character{Hero: "東方仗助"}
    newData := JojoData{Title: "ダイヤモンドは砕けない", Character: newCharacter}

    // JSON化して第4部のデータとして挿入します
    d, _ := json.Marshal(newData)
    db.Exec(insertQuery, 4, d)


    // SELECT
    rows, _ := db.Query("SELECT id, chapter, data as hero FROM jojo ORDER BY chapter ASC;")

    for rows.Next() {
        var jojo Jojo
        rows.Scan(&jojo.ID, &jojo.Chapter, &jojo.JojoData)

        // 取得したデータを構造体にマッピングします
        var d JojoData
        json.Unmarshal(jojo.JojoData, &d)

        pp.Println(fmt.Sprintf("第%d部", jojo.Chapter))
        pp.Println(d)
    }

}

実行してみます。

$ go run postgresql.go

"第1部"
main.JojoData{
  Title:     "ファントムブラッド",
  Character: main.Character{
    Hero: "ジョナサン・ジョースター",
  },
}
"第2部"
main.JojoData{
  Title:     "戦闘潮流",
  Character: main.Character{
    Hero: "ジョセフ・ジョースター",
  },
}
"第3部"
main.JojoData{
  Title:     "スターダストクルセイダース",
  Character: main.Character{
    Hero: "空条承太郎",
  },
}
"第4部"
main.JojoData{
  Title:     "ダイヤモンドは砕けない",
  Character: main.Character{
    Hero: "東方仗助",
  },
}

まとめ

GolangでPostgreSQLのJSONデータ型を読み書きする方法について書きました。

特にJSONだからといって難しいことはなく、普通にJSONのエンコード・デコードをしてあげれば大丈夫でした。実際はgorpgorm を使うことが多いと思いますが、上の基本を知っていればあまり迷うことはなさそうです。


『 Go 』Article List
Category List

Eye Catch Image
Read More

Androidに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

AWSに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Bitcoinに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

CentOSに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

dockerに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

GitHubに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Goに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Javaに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

JavaScriptに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Laravelに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Pythonに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Rubyに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Scalaに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Swiftに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Unityに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Vue.jsに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Wordpressに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

機械学習に関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。