我正在尝试从数据库中获取信息,而我的字段之一实际上是将JSON存储为字符串,并且我想将其作为结构获取。
这是我行的结构:
//there is json flag because I use it to get data from redis too
type InfoClip struct {
ClipId string `json:clipId`
StreamUrl string `json:streamUrl`
StartTimeCode int `json:startTimeCode`
EndTimeCode int `json:endTimeCode`
CreatedAt string `json:createdAt`
Metas string `json:metas` // here I get a string instead of a 'metas' struct
SourceId string `json:sourceId`
ProviderName string `json:providerName`
ProviderReference string `json:providerReference`
PublicationStatus string `json:publicationStatus`
UserId string `json:userId`
Name string `json:name`
FacebookPage string `json:facebookPage`
TwitterHandle string `json:twitterHandle`
PermaLinkUrl string `json:permalinkUrl`
Logo string `json:logo`
Link string `json:link`
}
这是我的
metas
结构:type metas struct {
Title string `json:title`
Tags []string `json:tags`
categories []string `json:permalink`
}
这就是我试图获取此字段的方式
func decodeJsonSql (met string) (*metas, error) {
m := metas{}
if err := json.Unmarshal([]byte(met), &m); err != nil {
fmt.Printf("Error decode metas: ", err)
return nil, err
} else {
return &m, err
}
}
func CheckIdSql(mediaId string) (error){
datab, err := sql.Open("mysql", "tcp()")
if err != nil {
fmt.Printf("[SQL ERROR] Cannot Open db => ", err)
return err
}
if err := datab.Ping(); err != nil {
fmt.Printf("[SQL ERROR] db connection => ", err)
return err
}
fmt.Printf("[SQL ONLINE] =>", datab)
defer datab.Close()
q := "SELECT c.id AS clipId, c.streamUrl, c.startTimecode, c.endTimecode, c.createdAt, s.metas,... FROM clips WHERE c.id = ?"
rows, err := datab.Query(q, mediaId)
if err != nil || err == sql.ErrNoRows {
fmt.Printf("SQL Err: %s", err)
return err
}
clips := InfoClip{}
for rows.Next() {
rows.Scan(&clips.ClipId, &clips.StreamUrl, &clips.StartTimeCode, &clips.EndTimeCode, &clips.CreatedAt, &clips.Metas, ...)
}
ret, err := decodeJsonSql(clips.Metas)
if err != nil{
return err
}
clips.Metas = ret
fmt.Printf("\n\n[SQL DEBUG RESPONSE]: %v", clips)
return nil
}
但是这个过程很繁琐,肯定有更简单的方法吗?
谢谢。
最佳答案
您可以使metas
结构实现 sql.Scanner
接口(interface)
它看起来应该像这样:
func (m *metas) Scan(src interface{}) error {
strValue, ok := src.(string)
if !ok {
return fmt.Errorf("metas field must be a string, got %T instead", src)
}
return json.Unmarshal([]byte(strValue), m)
}
之后,您可以将其用作
InfoClip
字段,并将其直接传递给Scan
并删除decodeJsonSql
:type InfoClip struct {
// [...]
Metas metas `json:metas`
// [...]
}
和
q := "SELECT c.id AS clipId, c.streamUrl, c.startTimecode, c.endTimecode, c.createdAt, s.metas,... FROM clips WHERE c.id = ?"
row := datab.QueryRow(q, mediaId)
clips := InfoClip{}
err := row.Scan(&clips.ClipId, &clips.StreamUrl, &clips.StartTimeCode, &clips.EndTimeCode, &clips.CreatedAt, &clips.Metas) // [...]
if err != nil {
fmt.Printf("SQL Err: %s", err)
return err
}
(顺便说一句,如您所见,由于您只期望一个结果,所以我用
datab.Query
替换了datab.QueryRow
)