No pude obtener el equivalente en Go + redigo de
HMSET myhash field1 "Hello" field2 "World"
para trabajar ("ERR número incorrecto de argumentos para el comando 'hmset'"). El soporte de hash nativo sería bueno para evitar esto y proporcionar funciones de conveniencia.
Redigo puede ejecutar cualquier comando, incluido HMSET. ¿Puede compartir la línea de código donde invoca HMSET?
package main
import (
"fmt"
"github.com/garyburd/redigo/redis"
"log"
)
var (
conn redis.Conn
)
// Connect to Redis
func init() {
var err error
conn, err = redis.Dial("tcp", ":6379")
if err != nil {
log.Fatalf("Couldn't connect to Redis: %v\n", err)
}
}
func main() {
defer conn.Close()
stockData := map[string]map[string]string{
"GOOG": {"company_name":"Google Inc.", "open_price":"803.99", "ask_price":"795.50", "close_price":"802.66", "bid_price":"793.36"},
"MSFT": {"ask_price":"N/A", "open_price":"28.30", "company_name":"Microsoft Corpora", "bid_price":"28.50", "close_price":"28.37"},
}
conn.Send("HMSET", "stocks")
// conn.Send("HMSET")
// conn.Send("stocks")
// var cmd []interface{}
for sym, row := range stockData {
for colName, val := range row {
key := sym + ":" + colName
// cmd = append(cmd, key, val)
conn.Send(key, val)
}
}
// conn.Send("HMSET", cmd...)
reply, err := conn.Do("EXEC")
if err != nil {
log.Fatalf("Error setting hash: %v\n", err)
}
fmt.Printf("reply == %+v\n", reply)
}
Los comentarios revelan las otras versiones que también he probado, como enviar (casi) todos los comandos a la vez con conn.Send("HMSET", cmd...)
. conn.Send("HMSET", "stocks", cmd...)
no se compila.
¿Alguna idea de lo que estoy haciendo mal?
Los siguientes ejemplos muestran cómo crear un hash para cada símbolo.
package main
import (
"github.com/garyburd/redigo/redis"
"log"
)
func main() {
conn, err := redis.Dial("tcp", ":6379")
if err != nil {
log.Fatalf("Couldn't connect to Redis: %v\n", err)
}
defer conn.Close()
stockData := map[string]map[string]string{
"GOOG": {"company_name": "Google Inc.", "open_price": "803.99", "ask_price": "795.50", "close_price": "802.66", "bid_price": "793.36"},
"MSFT": {"ask_price": "N/A", "open_price": "28.30", "company_name": "Microsoft Corpora", "bid_price": "28.50", "close_price": "28.37"},
}
// Example 1: Write command arguments out explicitly.
for sym, row := range stockData {
if _, err := conn.Do("HMSET", sym,
"company_name", row["company_name"],
"open_price", row["open_price"],
"ask_price", row["ask_price"],
"bid_price", row["bid_price"]); err != nil {
log.Fatal(err)
}
}
printAndDel(conn, "example 1", stockData)
// Example 2: Construct command arguments using range over a row map.
for sym, row := range stockData {
args := []interface{}{sym}
for k, v := range row {
args = append(args, k, v)
}
if _, err := conn.Do("HMSET", args...); err != nil {
log.Fatal(err)
}
}
printAndDel(conn, "example 2", stockData)
// Example 3: Construct command arguments using Redigo helper function.
for sym, row := range stockData {
if _, err := conn.Do("HMSET", redis.Args{sym}.AddFlat(row)...); err != nil {
log.Fatal(err)
}
}
printAndDel(conn, "example 3", stockData)
}
func printAndDel(conn redis.Conn, message string, stockData map[string]map[string]string) {
log.Print(message)
for sym := range stockData {
values, err := redis.Values(conn.Do("HGETALL", sym))
if err != nil {
log.Fatal(err)
}
log.Print(sym)
for i := 0; i < len(values); i += 2 {
log.Printf(" %s: %s", values[i], values[i+1])
}
}
for sym := range stockData {
if _, err := conn.Do("DEL", sym); err != nil {
log.Fatal(err)
}
}
}
Aquí hay otro ejemplo que usa struct en lugar de map. Este ejemplo almacena los datos en el mismo formato que los ejemplos anteriores.
package main
import (
"github.com/garyburd/redigo/redis"
"log"
)
type Stock struct {
CompanyName string `redis:"company_name"`
OpenPrice string `redis:"open_price"`
AskPrice string `redis:"ask_price"`
ClosePrice string `redis:"close_price"`
BidPrice string `redis:"bid_price"`
}
func main() {
conn, err := redis.Dial("tcp", ":6379")
if err != nil {
log.Fatalf("Couldn't connect to Redis: %v\n", err)
}
defer conn.Close()
stockData := map[string]*Stock{
"GOOG": &Stock{CompanyName: "Google Inc.", OpenPrice: "803.99", AskPrice: "795.50", ClosePrice: "802.66", BidPrice: "793.36"},
"MSFT": &Stock{AskPrice: "N/A", OpenPrice: "28.30", CompanyName: "Microsoft Corpora", BidPrice: "28.50", ClosePrice: "28.37"},
}
for sym, row := range stockData {
if _, err := conn.Do("HMSET", redis.Args{sym}.AddFlat(row)...); err != nil {
log.Fatal(err)
}
}
for sym := range stockData {
values, err := redis.Values(conn.Do("HGETALL", sym))
if err != nil {
log.Fatal(err)
}
var stock Stock
if err := redis.ScanStruct(values, &stock); err != nil {
log.Fatal(err)
}
log.Printf("%s: %+v", sym, &stock)
}
}
Grandes ejemplos, gracias! Leí un poco más y parece que Redis no admite hashes anidados, así que supongo que lo que estaba tratando de hacer no funcionará: crear un hash de Redis que contenga otro hash de símbolos a datos de valores. Puedo probar el truco probablemente lo suficientemente bueno de almacenar algo de JSON como una cadena, ya que eso es realmente lo que necesito.
De una forma u otra, podré hacer que esto funcione, especialmente con los ejemplos que ha dado. ¡Gracias de nuevo!
Los hash anidados no son compatibles. El breve y gratuito The Little Redis Book ofrece una buena descripción general de los tipos admitidos por Redis.
Es común almacenar JSON en Redis. Si solo está accediendo a los datos desde Go, codificar / gob es otra buena opción para almacenar datos anidados.
Comentario más útil
Aquí hay otro ejemplo que usa struct en lugar de map. Este ejemplo almacena los datos en el mismo formato que los ejemplos anteriores.