Reputation: 479
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
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
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
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