Marshal a list instead of each row to correct JSON?

I have this code that marshal a correct output as single rows.

var rows *sql.Rows
rows, err = db.Query(query)
cols, _ := rows.Columns()
colnames, _ := rows.Columns()
vals := make([]interface{}, len(cols))

for i, _ := range cols {  //bytes to string
   vals[i] = &cols[i]
}

mymap := make(map[string]interface{})

for i, v := range vals {  //adding column names
  mymap[colnames[i]] = v
}

for rows.Next() {
   err = rows.Scan(vals...)
   json, _ := json.Marshal(mymap)
   fmt.Fprintf(w,"%s\n",json)
}

The output will be as this:

{“ID”:“1”,“NAME”:“John Doe”}
{“ID”:“2”,“NAME”:“Jane Doe”}

But I need this as a block separated by commas :

[{“ID”:“1”,“NAME”:“John Doe”},
{“ID”:“2”,“NAME”:“Jane Doe”}]

As a complete newbie I think of marshal a complete list instead of each row

for rows.Next() {
   err = rows.Scan(vals...)
   append (list, vals)  //save to a list
}

json, _ := json.Marshal(list) //marshal the list instead of each row
fmt.Fprintf(w,"%s\n",json)

How do I do this?

Just create a slide to store your map and then marshall it.

var mySlice = make([]map[string]interface{}, 0)
for rows.Next() {
err = rows.Scan(vals…)
mySlice = append(mySlice, mymap)
}
json, _ := json.Marshal(mySlice)
fmt.Printf("%s\n", json)

HTH,
Yamil

I think this version is easier to follow

var arr []string
for rows.Next() {
err = rows.Scan(vals…)
m := make(map[string]interface{})
for i, v := range vals {
m[colnames[i]] = v
}
str, _ := json.Marshal(m)
arr = append(arr, string(str))
}

json, _ := json.Marshal(arr)
fmt.Println(string(json))

Thank you! I am just curious as a newbie. Does not this column iteration causing delay? Compared to your previous solution?

var mySlice = make([]map[string]interface{}, 0)
for rows.Next() {
   err = rows.Scan(vals…)
   mySlice = append(mySlice, mymap)
}

json, _ := json.Marshal(mySlice)
fmt.Printf("%s\n", json)

This deliver correct JSON, but same values ID 1 repeated:

[{“ID”:“1”,“NAME”:“John Doe”},
{“ID”:“1”,“NAME”:“John Doe”}]

Should be different values:

[{“ID”:“1”,“NAME”:“John Doe”},
{“ID”:“2”,“NAME”:“Jane Doe”}]

Any clue what is wrong?

You’re doing tricky stuff with pointers to a slice of values, and always scanning into the same slice (vals, containing pointers to cols), overriding the values. I appreciate that you’re trying to do something completely dynamic based on the table structure but the level of indirection in the initial code makes even me frown a bit.

You are dealing with a complete newbie on Golang. Learning by doing.

The main goal is to fetch data from SQL without knowing the struct AND parse this into JSON. I am beginning to think that this is either impossible or too hard for a newbie.

Hi, I did no test code so I got curious about why it return the same data always.
In the code below, I think a map is create in every call

var arr []map[string]interface{}
for rows.Next() {
err = rows.Scan(vals…)
m := make(map[string]interface{})
for i, v := range vals {
m[colnames[i]] = v
}
str, _ := json.Marshal(m)
fmt.Println(string(str))
arr = append(arr, m)
}
json, _ := json.Marshal(arr)
fmt.Println(string(json))

In fact, the data in the map is correctly shown and then the map (new pointer) is added to the slice so it is no possible to rewrite it. However,when write the slice, only shows the last one

Any hint for this ?
Regards,
Yamil

  var rows *sql.Rows
  rows, err = db.Query(query)
  cols, _ := rows.Columns()
  colnames, _ := rows.Columns()
  vals := make([]interface{}, len(cols))
 
  var arr []map[string]interface{}
  for rows.Next() {
    err = rows.Scan(vals...)
    m := make(map[string]interface{})
    for i, v := range vals {
      m[colnames[i]] = v
    }
  str, _ := json.Marshal(m)
  fmt.Println(string(str))
  arr = append(arr, m)
  }

Will return a single “null” as result. Any hint what I am doing wrong?

This is what happens:

Row 1: {“ID”:“1”,“NAME”: "John }
Row 2: {“ID”:“2”,“NAME”: “Jane Doe”}, {“ID”:“2”,“NAME”: “Jane Doe”}
Row 3: {“ID”:“3”,“NAME”: “Donald Duck”},{“ID”:“3”,“NAME”: “Donald Duck”},{“ID”:“3”,“NAME”: “Donald Duck”}

The rows.Scan fetches the correct values, but it appends AND replaces all previous values.

Any clue how to not replace previous values while looping through rows?

I got the solution from StackOverflow

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.