GORM 是 Golang 生態系中知名的 ORM(Object-Relational Mapping) 函式庫,如果想在 Golang 使用 ORM 相關的功能,不妨試試 GORM!

不過, GORM 文件中比較少篇幅提到 PostgreSQL 的 JSONB 如何使用,本文用以紀錄 GORM 使用 JSONB 的範例,如果沒使用 GORM 經驗的話,建議看過 GORM 文件後再閱讀本篇文章。

本文環境

  • mac0S 10.15
  • go 1.13.5
  • gorm 1.9.11
  • PostgreSQL 12

建議使用 Postgres.appPostico 在 macOS 上建置 PostgreSQL 環境。

JSONB 使用範例

以下是 GORM 的 PostgreSQL JSONB 使用範例:

package main

import (
    "encoding/json"
    "log"
    "fmt"

    "github.com/jinzhu/gorm"
    "github.com/jinzhu/gorm/dialects/postgres"
)

type UserPreference struct {
    gorm.Model
    UserId             string
    Preference         postgres.Jsonb `gorm:"default:'{}'"`
}

type PreferenceMap struct {
    SubscribeEDM bool     `json:"subscribe_edm"`
    PreferTopics []string `json:"prefer_topics"`
}

func (u *UserPreference) GetPreference() PreferenceMap {
    pm := PreferenceMap{}
    v, err := u.Preference.Value()
    if err != nil {
        log.Panicln(err)
    }
    err = json.Unmarshal(v.([]byte), &pm)
    if err != nil {
        log.Panicln(err)
    }
    return pm
}

func (u *UserPreference) SetPreference(v PreferenceMap) {
    b, err := json.Marshal(v)
    if err != nil {
        log.Panicln(err)
    }
    u.Preference = postgres.Jsonb{b}
}

func main() {
    connStr := fmt.Sprintf(
        "host=%s port=%s user=%s dbname=%s password=%s sslmode=disable",
        os.Getenv("POSTGRES_HOST"),
        os.Getenv("POSTGRES_PORT"),
        os.Getenv("POSTGRES_USER"),
        os.Getenv("POSTGRES_DBNAME"),
        os.Getenv("POSTGRES_PASSWORD"),
    )
    db, err := gorm.Open("postgres", connStr)
    if err != nil {
        panic(err)
    }
    db.AutoMigrate(UserPreference{})
    userPref := UserPreference{UserId: "1"}
    userPref.SetPreference(PreferenceMap{SubscribeEDM: true})
    db.Create(&userPref)

    userPref = UserPreference{}
    db.First(&userPref)
    fmt.Println(userPref.GetPreference())
}

上述範例主要在第 18 行定義 JSONB 欄位要存的結構之後,再分別實作 GetPreferenceSetPreference 2 個方法。

其中,第 25 行的 v, err := u.Preference.Value() 中的 Value() 能夠讓我們取得 JSONB 欄位中的值,接著才能在第 29 行利用 JSON package 提供的方法轉成我們要的資料結構。

而儲存 JSONB 的重點則是在第 41 行用 postgres.Jsonb 包裝起來的部分,必須用 postgres.Jsonb 才能順利將資料轉成 JSONB 。

以上, Happy Coding!

References

https://godoc.org/github.com/jinzhu/gorm/dialects/postgres?hide=1&import-graph=#Jsonb