【问题标题】:Casting json parts into Go structs from Redis using redigo使用 redigo 从 Redis 将 json 部分转换为 Go 结构
【发布时间】:2015-05-10 10:05:22
【问题描述】:

我有一个由浏览器发布的 json。这是一个带有

的哈希
var id int64 = 123 

比如说,三个像这样的字段:

myJson := `{ 
    "a":"{'x1':'apple','x2':'orange'}", 
    "b":"{'y1':345678,'y2':32456}", 
    "c":"['alpha@example1.com', 'beta@example2.com']"}`

然后使用 redigo 和命令将其存储在 Redis 中:

HMSET id:123 a "{'x1':'apple','x2':'orange'}" b "{'y1':345678,'y2':32456}" c "['alpha@example1.com', 'beta@example2.com']"

现在,我想在 Go 中使用这样的模型

type Model struct {
    A string `json:"a"`
    B string `json:"b"`
    C string `json:"c"` // Unknown length of map at runtime
}

1.我用

调用Redis
v, _ := redis.Values(c.Do("HGETALL", "id:123"))

我通过 redis-cli 看到正确存储的值,但是将 v 回复转换为 Model 结构不起作用:

var model Model
if err := redis.ScanStruct(v, &model); err != nil {
    panic(err)
}
fmt.Printf("c %#v\n", model.C) => empty []

我想访问单独的 k:v 对,例如:

B.y2 = 32456
C[0] = "alpha@example1.com"

2. 我还想将 json.Marshal myJson 作为 {a}、{a,b}、{a,c 的组合返回浏览器}、{a,b,c} 等。我不确定如何将各种 a、b、c 字段组合组合成一个进行编组。

任何帮助将不胜感激。

【问题讨论】:

    标签: json go redis redigo


    【解决方案1】:

    首先,您应该使用redis 而不是json 标记您的字段名称,这就是redigo 用于ScanStruct() 的方法。例如

    type Model struct {
        A string `redis:"a"`
        B string `redis:"b"`
        C string `redis:"c"` // Unknown length of map at runtime
    }
    

    其次,你的成员是字符串,所以你不能让个别成员访问他们的内容,我认为你不能用 redigo 自动化它。

    您可以,因为解决方法有一些扩展字符串的类型,并且有一个访问方法,可以将 json 延迟解析为底层 dict,然后返回值。像这样的东西(不经测试就写,只是一般的想法,我不确定它是否会起作用,但值得一试):

    type MyString string
    
    func (s MyString)Get(key string) (interface{}, error) {
       var m map[string]interface{}
    
       if err := json.Unmarshal([]byte(s), &m); err != nil {
           return nil, err
       } 
    
       return m[key], nil
    
    }
    

    它也不是很有效,因为它每次都会再次解析 json。 就我个人而言,我会将整个模型事物包装在一个结构中,该结构在从 redigo 反序列化的同时执行场景背后的所有逻辑。

    【讨论】:

    • json:"a" 等标签是我的剪切和粘贴错误,它们实际上是redis:"a" 等。我对您的建议很感兴趣,即“将整个模型的东西包装在一个结构中,该结构可以执行所有这些逻辑在从 redigo 反序列化时在幕后”,因为这正是我试图做的事情,但没有成功。换句话说,正如你所建议的那样,我想从{"a":"{'x':'t1', 'y':'t2', 'z':'t3'}"} 成为一个大字符串到 a.x, a.y, a.z 作为可寻址部分一次性通过结构。我只是不知道怎么做。任何提示将不胜感激。谢谢。
    • @parens 我向 redigo 提出了一个拉取请求,它可以实现你想要的 :) github.com/garyburd/redigo/issues/123 如果你愿意,你可以使用我的 fork
    • @parens 随时就 github 问题发表你的意见;)
    【解决方案2】:

    查看 RedisLabs 的 ReJSON 模块。

    我为它创建了一个简单的 go-client here 与 Redigo 一起使用。

    type Model struct {
        A string `redis:"a" json:"a"`
        B string `redis:"b" json:"b"`
        C string `redis:"c" json:"c"`
    }
    

    要读回它,请使用JSON.GET 命令,

    v, err := redis.Bytes(rejson.JSONGet(conn, "id:123", ""))
    if err != nil {
        return
    }
    
    m := new(Model)
    err = json.Unmarshal(v, m)
    if err != nil {
        return
    }
    

    【讨论】:

      【解决方案3】:
      type Model struct {
          A string `redis:"a" json:"a"`
          B string `redis:"b" json:"b"`
          C string `redis:"c" json:"c"`
      }
      

      您可以同时使用redis 标签和json 标签。
      ScanStruct 应该可以正常工作,它使用redis 标签。

      m := Model
      v, err := redis.Values(c.Do("HGETALL", key))
      err = redis.ScanStruct(v, &m)
      

      【讨论】:

        猜你喜欢
        • 2020-11-22
        • 2017-02-09
        • 1970-01-01
        • 1970-01-01
        • 2021-12-10
        • 1970-01-01
        • 1970-01-01
        • 2019-08-27
        • 1970-01-01
        相关资源
        最近更新 更多