[]string to jsonb with Gorm and postgres

大兔子大兔子 提交于 2020-11-29 03:12:31

问题


I have a Go struct which contains a slice of strings which I'd like to save as a jsonB object in Postgres with GORM.

I've come accross a solution which requires to use the GORM specific type (postgres.Jsonb) which I'd like to avoid.

When I try to run the AutoMigrate with a slice in my model, it panics and won't start although when I wrap this slice in a struct (which I'm okay doing) it will run without error but won't create the column in 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

Has anyone been able to manipulate jsonb with GORM without using the postgres.Jsonb type in models ?


回答1:


Maybe:

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"`
}



回答2:


Define a new type:

type Data map[string]interface{}

And implement the Valuer and Scanner interfaces onto them, which allows the field to be converted to a value for the database, and scanned back into the field, respectively:

// 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
}

Then you can define your field in your model like this:

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

Using the underlying map[string]interface{} type is nice too, as you can Unmarshal/Marshal any JSON to/from it.



来源:https://stackoverflow.com/questions/60092840/string-to-jsonb-with-gorm-and-postgres

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!