反序列化嵌套 JSON,或者简单地在 Go 中将其向前传递
Deserializing nested JSON, or simply pass it forward in Go
使用 Go 构建一个基本的 API,我已经将 JSON 存储在 postgres table 的 JSON 字段中,以及其他一些(普通)数据类型。使用我的模型,我只是想从数据库中获取一行并将其作为 JSON.
向前传递
使用 GORM 将数据反序列化为结构,大部分映射都是无缝发生的,除了 JSON,它根据所选数据类型呈现为字节数组或字符串。
以下是模型(更新):
type Item struct {
--snip--
Stats []ItemInfo `gorm:"column:stats" json:"stats" sql:"json"`
--snip--
}
type ItemInfo struct {
Stat string `json:"stat"`
Amount int `json:"amount"`
}
典型的 JSON 看起来像这样(来自数据库):
[{"stat": "Multistrike", "amount": 193}, {"stat": "Crit", "amount": 145},
{"stat": "Agility", "amount": 254}, {"stat": "Stamina", "amount": 381}]
所以我的想法是我只是想传递这个数据,而不是改变它,或者将它反序列化为 Go 结构或任何东西。 controller/route 如下:
func GetItem(c *gin.Context) {
id, err := strconv.Atoi(c.Param("id"))
// Convert Parameter to int, for db query
if err != nil {
panic(err)
}
// Get the DB context
db, ok := c.MustGet("databaseConnection").(gorm.DB)
if !ok {
// Do something
}
// Hold the structified item here.
var returnedItem models.Item
// Get the db row
db.Where(&models.Item{ItemID: id}).First(&returnedItem)
if c.Bind(&returnedItem) == nil {
// Respond with the struct as json
c.JSON(http.StatusOK, returnedItem)
}
}
响应如下 JSON(统计数据为 json.RawMessage):
{
"context": "raid-finder",
"stats": "W3sic3RhdCI6ICJWZXJzYXRpbGl0eSIsICJhbW91bnQiOiA0NX0sIHsic3RhdCI6ICJDcml0IiwgImFtb3VudCI6IDEwMH0sIHsic3RhdCI6ICJBZ2lsaXR5IiwgImFtb3VudCI6IDEwOX0sIHsic3RhdCI6ICJTdGFtaW5hIiwgImFtb3VudCI6IDE2M31d",
}
或者(将统计数据作为字符串):
{
"context": "raid-finder",
"stats": "[{\"stat\": \"Versatility\", \"amount\": 45}, {\"stat\": \"Crit\", \"amount\": 100}, {\"stat\": \"Agility\", \"amount\": 109}, {\"stat\": \"Stamina\", \"amount\": 163}]",
}
我有什么选项可以简单地传递它,到目前为止,我没有成功地尝试将 JSON 映射到结构(由于动态数据,这变得困难,以及我选择 [的原因=45=] 开头)?
我意识到 gin-gonic 发生了一些神奇的事情,c.JSON 自动(?)将结构中的所有数据编组到 JSON,但希望有一些方法可以避免编组 json 数据?
当 运行 使用 ItemInfo 子结构时,它会出现以下错误:
2016/01/07 08:21:08 Panic recovery -> reflect.Set: value of type []uint8 is not assignable to type []models.ItemInfo
/usr/local/go/src/runtime/panic.go:423 (0x42a929)
gopanic: reflectcall(nil, unsafe.Pointer(d.fn), deferArgs(d), uint32(d.siz), uint32(d.siz))
/usr/local/go/src/reflect/value.go:2158 (0x5492ce)
Value.assignTo: panic(context + ": value of type " + v.typ.String() + " is not assignable to type " + dst.String())
/usr/local/go/src/reflect/value.go:1327 (0x546195)
编辑:更新代码:
创建一个像 itemInfo
或类似的子结构:
type itemInfo struct {
Stat string `json:"stat"`
Crit int `json:"crit"`
}
然后在你的 Item
结构中 make
type Item struct {
--snip--
Context string `gorm:"column:context" json:"context"`
Stats []itemInfo `gorm:"column:stats" json:"stats" sql:"json"`
--snip--
}
然后当你解组时它应该进入项目信息!
此外,我假设您使用的是暴风雪 API,我已经制作了一个包装器,您可以在这里查看它:https://github.com/Gacnt/Go-WoW-API 看看我是如何完成的,但它完全未完成我只实现了我在做某事时需要的部分。
事实证明,最简单的方法是在 Item 结构中提供额外的 属性 以便 GORM 解组为 []byte,然后将字节数组解组为 sub-struct:
// Item is a thing..
type Item
Stats []byte `gorm:"column:stats" json:"stats"`
StatsList []ItemInfo `json:"iteminfo"`
}
并像这样解组:
err = json.Unmarshal(returnedItem.Stats, &returnedItem.StatsList)
感谢@evanmcdonnal 的建议。
使用 Go 构建一个基本的 API,我已经将 JSON 存储在 postgres table 的 JSON 字段中,以及其他一些(普通)数据类型。使用我的模型,我只是想从数据库中获取一行并将其作为 JSON.
向前传递使用 GORM 将数据反序列化为结构,大部分映射都是无缝发生的,除了 JSON,它根据所选数据类型呈现为字节数组或字符串。
以下是模型(更新):
type Item struct {
--snip--
Stats []ItemInfo `gorm:"column:stats" json:"stats" sql:"json"`
--snip--
}
type ItemInfo struct {
Stat string `json:"stat"`
Amount int `json:"amount"`
}
典型的 JSON 看起来像这样(来自数据库):
[{"stat": "Multistrike", "amount": 193}, {"stat": "Crit", "amount": 145},
{"stat": "Agility", "amount": 254}, {"stat": "Stamina", "amount": 381}]
所以我的想法是我只是想传递这个数据,而不是改变它,或者将它反序列化为 Go 结构或任何东西。 controller/route 如下:
func GetItem(c *gin.Context) {
id, err := strconv.Atoi(c.Param("id"))
// Convert Parameter to int, for db query
if err != nil {
panic(err)
}
// Get the DB context
db, ok := c.MustGet("databaseConnection").(gorm.DB)
if !ok {
// Do something
}
// Hold the structified item here.
var returnedItem models.Item
// Get the db row
db.Where(&models.Item{ItemID: id}).First(&returnedItem)
if c.Bind(&returnedItem) == nil {
// Respond with the struct as json
c.JSON(http.StatusOK, returnedItem)
}
}
响应如下 JSON(统计数据为 json.RawMessage):
{
"context": "raid-finder",
"stats": "W3sic3RhdCI6ICJWZXJzYXRpbGl0eSIsICJhbW91bnQiOiA0NX0sIHsic3RhdCI6ICJDcml0IiwgImFtb3VudCI6IDEwMH0sIHsic3RhdCI6ICJBZ2lsaXR5IiwgImFtb3VudCI6IDEwOX0sIHsic3RhdCI6ICJTdGFtaW5hIiwgImFtb3VudCI6IDE2M31d",
}
或者(将统计数据作为字符串):
{
"context": "raid-finder",
"stats": "[{\"stat\": \"Versatility\", \"amount\": 45}, {\"stat\": \"Crit\", \"amount\": 100}, {\"stat\": \"Agility\", \"amount\": 109}, {\"stat\": \"Stamina\", \"amount\": 163}]",
}
我有什么选项可以简单地传递它,到目前为止,我没有成功地尝试将 JSON 映射到结构(由于动态数据,这变得困难,以及我选择 [的原因=45=] 开头)?
我意识到 gin-gonic 发生了一些神奇的事情,c.JSON 自动(?)将结构中的所有数据编组到 JSON,但希望有一些方法可以避免编组 json 数据?
当 运行 使用 ItemInfo 子结构时,它会出现以下错误:
2016/01/07 08:21:08 Panic recovery -> reflect.Set: value of type []uint8 is not assignable to type []models.ItemInfo
/usr/local/go/src/runtime/panic.go:423 (0x42a929)
gopanic: reflectcall(nil, unsafe.Pointer(d.fn), deferArgs(d), uint32(d.siz), uint32(d.siz))
/usr/local/go/src/reflect/value.go:2158 (0x5492ce)
Value.assignTo: panic(context + ": value of type " + v.typ.String() + " is not assignable to type " + dst.String())
/usr/local/go/src/reflect/value.go:1327 (0x546195)
编辑:更新代码:
创建一个像 itemInfo
或类似的子结构:
type itemInfo struct {
Stat string `json:"stat"`
Crit int `json:"crit"`
}
然后在你的 Item
结构中 make
type Item struct {
--snip--
Context string `gorm:"column:context" json:"context"`
Stats []itemInfo `gorm:"column:stats" json:"stats" sql:"json"`
--snip--
}
然后当你解组时它应该进入项目信息!
此外,我假设您使用的是暴风雪 API,我已经制作了一个包装器,您可以在这里查看它:https://github.com/Gacnt/Go-WoW-API 看看我是如何完成的,但它完全未完成我只实现了我在做某事时需要的部分。
事实证明,最简单的方法是在 Item 结构中提供额外的 属性 以便 GORM 解组为 []byte,然后将字节数组解组为 sub-struct:
// Item is a thing..
type Item
Stats []byte `gorm:"column:stats" json:"stats"`
StatsList []ItemInfo `json:"iteminfo"`
}
并像这样解组:
err = json.Unmarshal(returnedItem.Stats, &returnedItem.StatsList)
感谢@evanmcdonnal 的建议。