2016-01-05 1 views
0

Création d'une API de base avec Go, j'ai JSON stocké dans un champ JSON dans une table postgres, avec quelques autres types de données (simples). À l'aide de mon modèle, j'essaie simplement d'extraire une ligne de la base de données et de la transmettre en tant que JSON.Désérialisation de JSON imbriqué, ou simplement transfert dans Go

En utilisant GORM pour désérialiser les données dans une structure, la plus grande partie du mappage se produit de manière transparente, à l'exception du JSON qui, selon le type de données sélectionné, se traduit par un bytearray ou une chaîne.

Voici les modèles (Mise à jour):

type Item struct { 
    --snip-- 
    Stats []ItemInfo `gorm:"column:stats" json:"stats" sql:"json"` 
    --snip-- 
} 

type ItemInfo struct { 
    Stat  string  `json:"stat"` 
    Amount  int   `json:"amount"` 
} 

Avec le JSON typique qui ressemble à ceci (à partir du DB):

[{"stat": "Multistrike", "amount": 193}, {"stat": "Crit", "amount": 145}, 
{"stat": "Agility", "amount": 254}, {"stat": "Stamina", "amount": 381}] 

L'idée est que je veux simplement passer ce données sur, ne pas le modifier, ou désérialiser à une structure Go ou quoi que ce soit. Le contrôleur suit/route:

func GetItem(c *gin.Context) { 
    id, err := strconv.Atoi(c.Param("id")) 

    // Convert Parameter to int, for db query 
    if err != nil { 
     panic(err) 
    } 

    // Get the DB context 
    db, ok := c.MustGet("databaseConnection").(gorm.DB) 
    if !ok { 
     // Do something 
    } 

    // Hold the structified item here. 
    var returnedItem models.Item 

    // Get the db row 
    db.Where(&models.Item{ItemID: id}).First(&returnedItem) 

    if c.Bind(&returnedItem) == nil { 

     // Respond with the struct as json 
     c.JSON(http.StatusOK, returnedItem) 
    } 
} 

qui répond à la JSON suivante (avec statistiques comme json.RawMessage):

{ 

    "context": "raid-finder", 
    "stats": "W3sic3RhdCI6ICJWZXJzYXRpbGl0eSIsICJhbW91bnQiOiA0NX0sIHsic3RhdCI6ICJDcml0IiwgImFtb3VudCI6IDEwMH0sIHsic3RhdCI6ICJBZ2lsaXR5IiwgImFtb3VudCI6IDEwOX0sIHsic3RhdCI6ICJTdGFtaW5hIiwgImFtb3VudCI6IDE2M31d", 
} 

Ou bien (avec des statistiques comme chaîne):

{ 
    "context": "raid-finder", 
    "stats": "[{\"stat\": \"Versatility\", \"amount\": 45}, {\"stat\": \"Crit\", \"amount\": 100}, {\"stat\": \"Agility\", \"amount\": 109}, {\"stat\": \"Stamina\", \"amount\": 163}]", 
} 

De quelles options ai-je besoin pour simplement transmettre ceci, jusqu'ici j'ai essayé sans succès de mapper le JSON à un struct (qui devient difficile à cause des données dynamiques, et la raison pour laquelle j'ai choisi JSON pour commencer)?

Je me rends compte qu'il y a de la magie à partir de gin-gonic, avec c.JSON automatiquement (?) Rassemblant toutes les données de la structure en JSON, mais en espérant qu'il y ait un moyen d'éviter de rassembler les données json?

Quand couru avec le substruct itemInfo, il affole avec l'erreur suivante:

2016/01/07 08:21:08 Panic recovery -> reflect.Set: value of type []uint8 is not assignable to type []models.ItemInfo 
/usr/local/go/src/runtime/panic.go:423 (0x42a929) 
     gopanic: reflectcall(nil, unsafe.Pointer(d.fn), deferArgs(d), uint32(d.siz), uint32(d.siz)) 
/usr/local/go/src/reflect/value.go:2158 (0x5492ce) 
     Value.assignTo: panic(context + ": value of type " + v.typ.String() + " is not assignable to type " + dst.String()) 
/usr/local/go/src/reflect/value.go:1327 (0x546195) 

EDIT: Code Mise à jour:

+0

Pourrait fournir une réponse complète plus tard, mais ma suggestion est assez simple, ajouter un champ supplémentaire à votre type pour représenter le json comme un [] octet, laissez GORM unmarshal dans cela. Après cela, utilisez 'encoding/json' pour démélanger le' [] byte' dans la structure cible. – evanmcdonnal

+0

Je me sens mal parce que j'ai manqué votre commentaire, et il s'est avéré être une solution super facile. Merci beaucoup! –

Répondre

0

se avère qu'il était plus facile de simplement fournir une propriété supplémentaire dans le struct article pour GORM à unmarshal dans [] octet puis unmarshal le tableau d'octets comme sous-struct:

// Item is a thing.. 
type Item 
    Stats   []byte `gorm:"column:stats" json:"stats"` 
    StatsList  []ItemInfo `json:"iteminfo"` 
} 

Et unmarshal comme ceci:

err = json.Unmarshal(returnedItem.Stats, &returnedItem.StatsList) 

Merci à @evanmcdonnal pour la suggestion.

0

Faire un struct sous comme itemInfo ou quelque chose comme:

type itemInfo struct { 
    Stat string `json:"stat"` 
    Crit int `json:"crit"` 
} 

Puis dans votre Item struct make

type Item struct { 
    --snip-- 
    Context string `gorm:"column:context" json:"context"` 
    Stats []itemInfo `gorm:"column:stats" json:"stats" sql:"json"` 
    --snip-- 
} 

Ensuite, lorsque vous vous effusez, il devrait aller très bien dans l'information de l'article!

Aussi, je suppose que vous utilisez API blizzards, j'ai déjà fait un emballage, vous pouvez le voir ici: https://github.com/Gacnt/Go-WoW-API pour voir comment je l'ai fait, mais il est complètement inachevé, je n'ai mis en place que les pièces dont j'avais besoin travaillait sur quelque chose.

+0

Merci pour la réponse. J'ai mis en place un sous-struct comme votre exemple, qui provoque malheureusement la panique lors de l'extraction de la ligne avec l'ORM, avec le message suivant: '2016/01/06 17:20:35 Panic recovery -> reflect .Set: valeur de type [] uint8 n'est pas affectable à type [] models.ItemInfo' J'ai essayé de jouer avec le type de données dans model.ItemInfo, en changeant entre int/string, sans vraiment de chance. –

+0

@ PerFröjd Pouvez-vous mettre votre code dans votre question afin que je puisse le voir? – Datsik

+0

Question mise à jour avec de nouvelles structures et l'exception –