Não consegui obter o equivalente Go + redigo de
HMSET myhash field1 "Hello" field2 "World"
para funcionar ("ERR número errado de argumentos para o comando 'hmset'"). O suporte nativo de hash seria bom para contornar isso e fornecer funções convenientes.
Redigo pode executar qualquer comando incluindo HMSET. Você pode compartilhar a linha de código onde invoca o 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)
}
Os comentários revelam as outras versões que também experimentei, como enviar (quase) todos os comandos de uma vez com conn.Send("HMSET", cmd...)
. conn.Send("HMSET", "stocks", cmd...)
não compila.
Alguma ideia do que estou fazendo de errado?
Os exemplos a seguir mostram como criar um 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)
}
}
}
Aqui está outro exemplo que usa struct em vez de map. Este exemplo armazena os dados no mesmo formato dos exemplos 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)
}
}
Ótimos exemplos, obrigado! Eu li um pouco mais e parece que o Redis não oferece suporte a hashes aninhados, então suponho que o que eu estava tentando fazer não funcionaria: criar um hash Redis que contém outro hash de símbolos para dados de estoque. Posso tentar o truque provavelmente bom o suficiente de armazenar alguns JSON como string, já que é disso que realmente preciso.
De uma forma ou de outra, poderei fazer isso funcionar, especialmente com os exemplos que você deu. Obrigado novamente!
Hashes aninhados não são suportados. O pequeno e gratuito The Little Redis Book oferece uma boa visão geral dos tipos suportados pelo Redis.
É comum armazenar JSON no Redis. Se você estiver acessando apenas os dados do Go, codificar / gob é outra boa opção para armazenar dados aninhados.
Comentários muito úteis
Aqui está outro exemplo que usa struct em vez de map. Este exemplo armazena os dados no mesmo formato dos exemplos anteriores.