douwu5428
douwu5428
2017-06-27 02:34

如何在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 douzao2992 4年前

    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 dongzhang7961 4年前

    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 duandao2306 3年前

    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

    点赞 评论 复制链接分享

相关推荐