douwu5428
2017-06-27 02:34
浏览 277

如何在Golang中将数组文档设置为Redis?

I have a problemwhen insert document in to redis.

I have a struct of data in Go:

type ArticleCovers struct {
    ID             int
    Covers         ArticleCovers
    ArticleTypeID  int
    Address        Address     `gorm:"ForeignKey:AddressID"`
}

I want to add a data like this into Redis:

[ID:1 Cover:[http://chuabuuminh.vn/UserImages/2012/12/10/1/chinh_dien_jpg.jpg] ArticleTypeID:1 Address:map[Street: City:<nil> District:<nil> DistrictID:0 ID:0 Slug: Lat:0 Long:0 Ward:<nil> WardID:0 CityID:0]] 

But when I run Redis.HMSet("test", structs.Map(ret)) it return the error: redis: can't marshal postgresql.ArticleCovers (consider implementing encoding.BinaryMarshaler).

Who can help me fix my problem, thks you so much!

  • 写回答
  • 好问题 提建议
  • 关注问题
  • 收藏
  • 邀请回答

3条回答 默认 最新

  • douzao2992 2017-06-27 05:29
    已采纳

    Like the error message says, you need to implement the BinaryMarshaler interface for your ArticleCovers type:

    type ArticleCovers struct {
        ID             int
        Covers         ArticleCovers
        ArticleTypeID  int
        Address        Address     `gorm:"ForeignKey:AddressID"`
    }
    
    func (ac ArticleCovers) MarshalBinary() ([]byte, error) {
        return []byte(fmt.Sprintf("%v-%v", ac.ID, ac.ArticleTypeID)), nil
    }
    

    Note that this only adds the ID and ArticleTypeID fields. I don't know what the ArticleCovers and Address types look like, but often you want to call the same methods on that:

    func (ac ArticleCovers) MarshalBinary() ([]byte, error) {
        covers, err := ac.Covers.MarshalBinary()
        if err != nil {
            return nil, err
        }
        address, err := ac.Address.MarshalBinary()
        if err != nil {
            return nil, err
        }
    
        return []byte(fmt.Sprintf("%v-%v-%v-%v",
            ac.ID, ac.ArticleTypeID, covers, address)
    }
    

    I don't know if this format makes sense for your data. You may want to use a defined encoding format such as json.

    You will probably also want to implement the BinaryUnmarshaler interface. Doing that is left as an exercise ;-)

    已采纳该答案
    评论
    解决 无用
    打赏 举报
  • dongzhang7961 2017-09-22 13:55

    As Carpetsmoker was saying about the JSON encoding this is how to do it:

    func (ac ArticleCovers) MarshalBinary() ([]byte, error) {
      return json.Marshal(ac)
    }
    

    Where when decoding you'd use BinaryUnmarshaler

    You can checkout for better example here at my blog post

    评论
    解决 无用
    打赏 举报
  • duandao2306 2018-07-04 19:28

    When saving any kind of object into redis directly, it tries to binary hash it so you should implement MarshalBinary to make it work. the idea is to save the value simply in a binary format or string format that is handled by the client internally.

    So with that being said, one possible and easy solution of saving objects is save them in a string format, you can still use different marshaling techniques like JSON to do this.

    func Save(obj interface{}) error {
      Redis.HMSet("test", json.Marshal(obj))
    }
    

    Although json is an easy way of doing this, but you can have better performance by using binary instead of text-based encoding. gop is package where it can encode and decode objects. also protocol buffers is now widely used especially in such cases where we have different languages and integrations.

    Here is a simple example with gop and MarshalBinary

    评论
    解决 无用
    打赏 举报

相关推荐 更多相似问题