【问题标题】:[]string to jsonb with Gorm and postgres[]string 到 jsonb 与 Gorm 和 postgres
【发布时间】:2020-05-22 08:58:12
【问题描述】:

我有一个 Go 结构,其中包含一段字符串,我想用 GORM 在 Postgres 中将其保存为 jsonB 对象。

我遇到了一个解决方案,它需要使用我想避免的 GORM 特定类型 (postgres.Jsonb)。

当我尝试在我的模型中使用切片运行 AutoMigrate 时,它​​会出现恐慌并且不会启动,尽管当我将此切片包装在一个结构中时(我可以这样做),它会运行而不会出错但不会在 postgres 中创建列。

type User struct {
        gorm.Model
        Data []string `sql:"type:"jsonb"; json:"data"`
} //Panics

type User struct {
        gorm.Model
        Data struct {
            NestedData []string
        } `sql:"type:"jsonb"; json:"data"`
} //Doesn't crash but doesn't create my column

有没有人能够在不使用模型中的 postgres.Jsonb 类型的情况下使用 GORM 操作 jsonb ?

【问题讨论】:

    标签: postgresql go jsonb go-gorm


    【解决方案1】:

    也许:

    type DataJSONB []string
    
    func (dj DataJSONB) Value() (driver.Value, error) {
        return json.Marshal(dj)
    }
    
    func (dj *DataJSONB) Scan(value interface{}) error {
        b, ok := value.([]byte)
        if !ok {
            return fmt.Errorf("[]byte assertion failed")
        }
    
        return json.Unmarshal(b, dj)
    }
    
    // Your bit
    type User struct {
        gorm.Model
        Data DataJSONB `sql:"type:"jsonb"; json:"data"`
    }
    

    【讨论】:

    • 我得到这个错误:struct field tag sql:"type:"jsonb";json:"studs" not compatible with reflect.StructTag.Get: key:"value" 对没有用空格structtag 分隔
    【解决方案2】:

    定义一个新类型:

    type Data map[string]interface{}
    

    并在它们上实现ValuerScanner 接口,这允许将字段转换为数据库的,然后扫描回到字段,分别:

    // Value converts into []byte
    func (d Data) Value() (driver.Value, error) {
      j, err := json.Marshal(d)
      return j, err
    }
    
    // Scan puts the []byte back into Data
    func (d *Data) Scan(src interface{}) error {
      source, ok := src.([]byte)
      if !ok {
        return errors.New("Type assertion .([]byte) failed.")
      }
    
      var i interface{}
      if err := json.Unmarshal(source, &i); err != nil {
        return err
      }
    
      *d, ok = i.(map[string]interface{})
      if !ok {
        return errors.New("Type assertion .(map[string]interface{}) failed.")
      }
    
      return nil
    }
    

    然后你可以像这样在你的模型中定义你的字段:

    type User struct {
            gorm.Model
            Data Data `type: jsonb not null default '{}'::jsonb`
    }
    

    使用底层的map[string]interface{} 类型也很好,因为你可以Unmarshal/Marshal 任何JSON 传入/传出它。

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-16
    • 2016-11-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多