Reputation: 11
I'm trying to convert a []*Struct
to a JSON response. I'm able to get the data from the []*Struct
and iterate over it. The part I get stuck around is the iterating over a loop and then returning the data to an interface{}
.
I've tried to putting an interface in an interface, but I just can't make ends meet. Here's what I have at the moment; I was told to turn to Stack Overflow if I had any issues.
package main
import (
"log"
"context"
"cloud.google.com/go/datastore"
)
var ctx = context.Background()
type ItemList struct {
Id string `datastore:"_id"`
Name string `datastore:"name"`
}
type Data struct {
ManyItems []Item
}
type Item struct {
Id string `json:"id"`
Name string `json:"name"`
}
func Get() ([]*ItemList, error) {
client, err := datastore.NewClient(ctx, "project-name")
if err != nil {
log.Println(err)
}
var Response []*ItemList
query := datastore.NewQuery("query")
_, err = client.GetAll(ctx, query, &Response)
if err != nil {
log.Println(err)
}
return Response, error
}
func Read() (interface{}) {
resp, err := Get()
if err != nil {
log.Println(err)
}
for i, _ := range resp {
// this is where i get stuck
r := &Data{
ManyItems: Item{
Id: resp[i].Id,
Name: resp[i].Name,
},
}
return r
}
}
How can I do it?
Upvotes: 1
Views: 11848
Reputation: 2047
You are returning inside the for loop and this will only return the first item.
Also I see that ManyItems is an array of Item ([]Item) and you are assigning a single Item which is wrong.
Update: Here you have the complete code:
// Input Json data
type ItemList struct {
Id string `datastore:"_id"`
Name string `datastore:"name"`
}
//Convert *ItemList to *Item
func (list *ItemList) ToItem() *Item {
return &Item {
Id : list.Id,
Name : list.Name,
}
}
// Output Json data
type Data struct {
ManyItems []*Item `json:"data"`
}
//Output json item object
type Item struct {
Id string `json:"id"`
Name string `json:"name"`
}
// The read function
func Read() (string, error) {
resp, err := Get()
if err != nil {
log.Println(err)
return "", err
}
list := make([]Item, len(resp))
for i, _ := range resp {
list[i] = resp[i].ToItem()
}
b, err := json.Marshal(&Data{list})
if err != nil {
fmt.Println(err)
return "", err
}
return string(b), nil
}
Test: Playground
Upvotes: 3
Reputation: 38303
You can predeclare a *Data
variable and then inside the loop, on each iteration add the item to its ManyItems
field. Since ItemList
and Item
have the same structure, ie the same fields in the same order, you can convert directly one to the other. (As long as you are on Go 1.8 or newer)
func Read() interface{} {
resp, err := Get()
if err != nil {
log.Println(err)
return nil
}
data := &Data{ManyItems: make([]Item, len(resp))}
for i := range resp {
data.ManyItems[i] = Item(*resp[i])
}
return data
}
However if possible it would be more efficient to just return the slice you already have, something like this.
type ItemList struct {
Id string `datastore:"_id" json:"id"`
Name string `datastore:"name" json:"name"`
}
type Data struct {
ManyItems []*ItemList
}
func Read() interface{} {
resp, err := Get()
if err != nil {
log.Println(err)
return nil
}
return &Data{ManyItems: resp}
}
Upvotes: 2