gorm中正确使用json数据类型

2,619 阅读2分钟

一、说明

  • 1、JSON 数据类型是 MySQL 5.7.8 开始支持的。在此之前,只能通过字符类型(CHARVARCHARTEXT )来保存 JSON 文档。现实中也很多人不会采用json的存储方式,直接定义一个字符类型,让前端转换传递进来,返回给前端也是一个字符串,前端自己处理

  • 2、参考文档

  • 3、创建一个数据表

    CREATE TABLE `report` (
      `id` int NOT NULL AUTO_INCREMENT COMMENT '主键id',
      `query_param` json NOT NULL,
      `name` varchar(50) DEFAULT NULL,
      `created_at` timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) COMMENT '创建时间',
      `updated_at` timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6) COMMENT '更新时间',
      `deleted_at` timestamp(6) NULL DEFAULT NULL COMMENT '软删除时间',
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
    

二、gorm中使用json方式一

  • 1、自定义数据类型

    // JSON 自定义JSON数据类型
    type JSON []byte
    
    func (j JSON) Value() (driver.Value, error) {
     if j.IsNull() {
        return nil, nil
     }
     return string(j), nil
    }
    func (j *JSON) Scan(value interface{}) error {
     if value == nil {
        *j = nil
        return nil
     }
     s, ok := value.([]byte)
     if !ok {
        errors.New("invalid Scan Source")
     }
     *j = append((*j)[0:0], s...)
     return nil
    }
    func (m JSON) MarshalJSON() ([]byte, error) {
     if m == nil {
        return []byte("null"), nil
     }
     return m, nil
    }
    func (m *JSON) UnmarshalJSON(data []byte) error {
     if m == nil {
        return errors.New("null point exception")
     }
     *m = append((*m)[0:0], data...)
     return nil
    }
    func (j JSON) IsNull() bool {
     return len(j) == 0 || string(j) == "null"
    }
    func (j JSON) Equals(j1 JSON) bool {
     return bytes.Equal([]byte(j), []byte(j1))
    }
    
  • 2、在配置生成实体类的工具中遇到json的话直接转换为JSON数据类型

    dataMap := map[string]func(detailType gorm.ColumnType) (dataType string){
     "json":      func(detailType gorm.ColumnType) (dataType string) { return "JSON" },      // 自定义 
    }
    
  • 3、逆向生成的实体类

    type ReportEntity struct {
     ID         int64          `gorm:"column:id;type:int;primaryKey;autoIncrement:true;comment:主键id" json:"id"` // 主键id
     QueryParam JSON           `gorm:"column:query_param;type:json;not null" json:"queryParam"`
     Name       string         `gorm:"column:name;type:varchar(50)" json:"name"`
     CreatedAt  LocalTime      `gorm:"column:created_at;comment:创建时间" json:"createdAt"`            // 创建时间
     UpdatedAt  LocalTime      `gorm:"column:updated_at;comment:更新时间" json:"updatedAt"`            // 更新时间
     DeletedAt  gorm.DeletedAt `gorm:"column:deleted_at;type:timestamp(6);comment:软删除时间" json:"-"` // 软删除时间
    }
    
  • 4、定义DTO的时候直接定义JSON数据类型

    type Test1Dto struct {
     QueryParam JSON `json:"queryParam"`
     Name       string         `json:"name"`
    }
    
  • 5、随便插入数据

    image-20230823091230959.png

三、定义JSON的方式二

  • 1、直接使用gorm自带的json数据类型datatypes.JSON
  • 2、可以自己再次封装下

四、查询语句

  • 1、官方案例地址

  • 2、查询对象中的数据

    first, _ := dao.ReportEntity.WithContext(ctx).
        Where(gen.Cond(datatypes.JSONQuery("query_param").Extract("gender").Equals("男"))...).First()
    
    SELECT * FROM `report` WHERE JSON_EXTRACT(`query_param`,'$.gender') AND `report`.`deleted_at` IS NULL ORDER BY `report`.`id` LIMIT 1
    

image-20230823092019762.png

  • 3、查询数组中是否包括元素

    first, _ := dao.ReportEntity.WithContext(ctx).Where(gen.Cond(datatypes.JSONArrayQuery("query_param").Contains("1"))...).First()
    
     SELECT * FROM `report` WHERE JSON_CONTAINS (`query_param`, JSON_ARRAY('1')) AND `report`.`deleted_at` IS NULL ORDER BY `report`.`id` LIMIT 1
    

    image-20230823092108902.png

  • 4、查询对象数组中是否包括一个值(官网上没找到合适的方式,只能写原生sql)

    SELECT * from report WHERE query_param->"$[1].age" = 20;
    
    first := model.ReportEntity{}
    w.db.Raw(`SELECT * from report WHERE query_param->"$[1].age" = 20;`).Scan(&first)
    

image-20230823092353059.png