user3453838
user3453838

Reputation: 479

How to set array document into redis in Golang?

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!

Upvotes: 1

Views: 10207

Answers (3)

Muhammad Soliman
Muhammad Soliman

Reputation: 23796

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

Upvotes: 0

Nevio Vesić
Nevio Vesić

Reputation: 365

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

Upvotes: 1

Martin Tournoij
Martin Tournoij

Reputation: 27822

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 ;-)

Upvotes: 3

Related Questions