Search code examples
goredisredigo

How can I save and retrieve a map into redis using redigo?


I have a map like this, which I want to save/retrive from redis using redigo:

animals := map[string]bool{
    "cat": true,
    "dog":   false,
    "fox": true,
}

The length of the map may vary.

I tried these function:

func SetHash(key string, value map[string]bool) error {
    conn := Pool.Get()
    defer conn.Close()
    _, err := conn.Do("HMSET", key, value)
    if err != nil {
        return fmt.Errorf("error setting key %s to %s: %v", key, value, err)
    }
    return err
}


func GetHash(key string) (map[string]bool, error) {
    conn := Pool.Get()
    defer conn.Close()
    val, err := conn.Do("HGETALL", key)
    if err != nil {
        fmt.Errorf("error setting key %s to %s: %v", key, nil, err)
        return nil,  err
    }
    return val, err
}

But can not make GetHash correctly. I've checked the docs examples and it was not helpful. So appreciate your help to have a working example.


Solution

  • The application is responsible for converting structured types to and from the types understood by Redis.

    Flatten the map into a list of arguments:

    func SetHash(key string, value map[string]bool) error {
        conn := Pool.Get()
        defer conn.Close()
    
        // Create arguments: key field value [field value]...
        var args = []interface{}{key}
        for k, v := range value {
            args = append(args, k, v)
        }
    
        _, err := conn.Do("HMSET", args...)
        if err != nil {
            return fmt.Errorf("error setting key %s to %v: %v", key, value, err)
        }
        return err
    }
    

    Convert the returned field value pairs to a map:

    func GetHash(key string) (map[string]bool, error) {
        conn := Pool.Get()
        defer conn.Close()
        values, err := redis.Strings(conn.Do("HGETALL", key))
        if err != nil {
            return nil, err
        }
    
            // Loop through [field value]... and parse value as bool.
        m := map[string]bool{}
        for i := 0; i < len(values); i += 2 {
            b, err := strconv.ParseBool(value)
            if err != nil {
                return nil, errors.New("value not a bool")
            }
            m[key] = b
        }
        return m, nil
    }