gorm - 支持mysql json类型

11,005 阅读1分钟

背景

项目常用关系型数据库MYSQL,理论上遵循范式,应该为每个模型设计一个表,减少表之间冗余数据 往往实际业务会有很多冗长/相似/无需(或者极少情况需要)索引的数据, 举个例子:

{
    "id":"-LsaoCreHzrHXQ4sKseq",
    "name":"123",
    "image":{
        "uid":"ba791a9c-56bf-43c9-8317-9b4efe19ef3b",
        "name":"inside_corbit.png",
        "url":"https://corbit-dev-868303926763-us-east-1.s3.amazonaws.com/cms/prod/world/-LsanywxSrSpx1T_0AVF/topic/-LsaoCreHzrHXQ4sKseq/inside_corbit.png",
        "size":99802,
        "status":"done"
    },
    "introAudio":{
        "uid":"ab856fb2-076b-46ac-afb7-32b8caf86a00",
        "name":"circuits_video_intro.mp3",
        "url":"https://corbit-dev-868303926763-us-east-1.s3.amazonaws.com/cms/prod/world/-LsanywxSrSpx1T_0AVF/topic/-LsaoCreHzrHXQ4sKseq/circuits_video_intro.mp3",
        "size":88868,
        "status":"done"
    },
    "celebrations":[
        {
            "audio":{
                "uid":"c34a588c-e008-4bf8-9054-77fe907122fb",
                "name":"circuits_video_intro.mp3",
                "url":"https://corbit-dev-868303926763-us-east-1.s3.amazonaws.com/cms/prod/world/-LsanywxSrSpx1T_0AVF/topic/-LsaoCreHzrHXQ4sKseq/circuits_video_intro.mp3",
                "size":88868,
                "status":"done"
            }
        }
    ]
}

面对这种情况,去设计多个关联表必然是一个复杂的工作。如果项目存在大量这种需求,可能需要审视数据库选型,是否非关系型数据库更为合适。

针对其他原因,使用Mysql的情况下,可以使用mysql json特性

gorm + json

源码

package main

import (
	"database/sql/driver"
	"encoding/json"
	"fmt"
	"github.com/jinzhu/gorm"
	_ "github.com/jinzhu/gorm/dialects/mysql"
)

// model
type Medium struct {
	URL  string `json:"url"`
	Name string `json:"name"`
}

type Demo struct {
	Id    uint64
	Icon  Medium     `gorm:"TYPE:json"`
}

func (c Medium) Value() (driver.Value, error) {
	b, err := json.Marshal(c)
	return string(b), err
}

func (c *Medium) Scan(input interface{}) error {
	return json.Unmarshal(input.([]byte), c)
}


func main(){
	// connect db
	config := fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8mb4&parseTime=%t&loc=%s",
		"root",
		"123",
		"localhost:3306",
		"go-to-gorm",
		true,
		"Local")

	db, _ := gorm.Open("mysql", config)

	// construct data
	names := []string{
		"aa",
		"bb",
		"cc",
		"dd",
		"ee",
	}
	for i:=0; i< 5; i++ {
		demo := Demo{
			Icon: Medium{
				URL:"http://makeblock.com/" + names[i],
				Name:names[i],
			},
		}
		fmt.Println(demo.Icon)
		db.Table("demo").Create(&demo)
	}

	//search json filed
	var item Demo
	db.Table("demo").Where("icon->'$.name' = (?)", names[4]).First(&item)
	fmt.Println(item)

}

模型函数

为模型实现Value/Scan函数

func (c Medium) Value() (driver.Value, error) {
	b, err := json.Marshal(c)
	return string(b), err
}

func (c *Medium) Scan(input interface{}) error {
	return json.Unmarshal(input.([]byte), c)
}

添加json类型标签

type Demo struct {
	Id    uint64
	Icon  Medium     `gorm:"TYPE:json"`
}

获取json类型属性

db.Table("demo").Where("icon->'$.name' = (?)", names[4]).First(&item)