Как добавить последнюю строку SQL в список без замены предыдущих строк в Golang - PullRequest
0 голосов
/ 28 апреля 2018

Этот код доставляет AFAIK правильный вывод JSON [{}, {}], но каждая строка добавляется и заменяет все предыдущие строки, поэтому в результате отображаются только копии последней строки.

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

for i, _ := range cols {
   vals[i] = &cols[i]
}

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

for i, val := range vals {
  m[colnames[i]] = val
}

list := make([]map[string]interface{}, 0)
for rows.Next() {
err = rows.Scan(vals...)
   list = append(list, m)
}
json, _ := json.Marshal(list)
fmt.Fprintf(w,"%s\n", json)

Вот что происходит за кулисами, проходящими через строки:

цикл 1: {«ИД»: «1», «ИМЯ»: «Джон»

цикл 2: {«ИД»: «2», «ИМЯ»: «Джейн Доу»} {«ИД»: «2», «ИМЯ»: «Джейн Доу»}

цикл 3: {«ИД»: «3», «ИМЯ»: «Дональд Дак»} {«ИД»: «3», «ИМЯ»: «Дональд Дак»} {«ИД»: «3» , «ИМЯ»: «Дональд Дак»}

rows.Scan выбирает правильные значения, но добавляет И заменяет все предыдущие значения.

Окончательный вывод - это

[{«ИД»: «3», «ИМЯ»: «Дональд Дак»}, {«ИД»: «3», «ИМЯ»: «Дональд Дак»}, {«ИД»: «3») , «ИМЯ»: «Дональд Дак»}]

Но должно быть так:

[{«ID»: «1», «NAME»: «John Doe»}, {«ID»: «2», «NAME»: «Jane Doe»}, {«ID»: «3») , «ИМЯ»: «Дональд Дак»}]

Что я делаю не так?

Вы можете понизить это, но, пожалуйста, объясните, почему. Я все еще новичок на Голанге и хочу учиться.

1 Ответ

0 голосов
/ 28 апреля 2018

Я исправил это и объяснил с комментариями, что вы сделали не так:

// 1. Query
var rows *sql.Rows
rows, err = db.Query(query)
cols, _ := rows.Columns()

// 2. Iterate
list := make([]map[string]interface{}, 0)
for rows.Next() {
    vals := make([]interface{}, len(cols))
    for i, _ := range cols {
        // Previously you assigned vals[i] a pointer to a column name cols[i].
        // This meant that everytime you did rows.Scan(vals),
        // rows.Scan would see pointers to cols and modify them
        // Since cols are the same for all rows, they shouldn't be modified.

        // Here we assign a pointer to an empty string to vals[i],
        // so rows.Scan can fill it.
        var s string
        vals[i] = &s

        // This is effectively like saying:
        // var string1, string2 string
        // rows.Scan(&string1, &string2)
        // Except the above only scans two string columns
        // and we allow as many string columns as the query returned us — len(cols).
    }

    err = rows.Scan(vals...)

    // Don't forget to check errors.
    if err != nil {
        log.Fatal(err)
    }

    // Make a new map before appending it.
    // Remember maps aren't copied by value, so if we declared
    // the map m outside of the rows.Next() loop, we would be appending
    // and modifying the same map for each row, so all rows in list would look the same.
    m := make(map[string]interface{})
    for i, val := range vals {
        m[cols[i]] = val
    }
    list = append(list, m)
}

// 3. Print.
b, _ := json.MarshalIndent(list, "", "\t")
fmt.Printf("%s\n", b)

Не волнуйтесь, мне было трудно понять, когда я был новичком.

Теперь что-нибудь веселое:

var list []map[string]interface{}
rows, err := db.Queryx(query)
for rows.Next() {
    row := make(map[string]interface{})
    err = rows.MapScan(row)
    if err != nil {
      log.Fatal(err)
    }
    list = append(list, row)
}

b, _ := json.MarshalIndent(list, "", "\t")
fmt.Printf("%s\n", b)

Это аналогично коду выше, но с sqlx . Немного проще, нет?

sqlx - это расширение поверх database/sql с методами сканирования строк непосредственно на картах и ​​структурах, поэтому вам не нужно делать это вручную.

Я думаю, что ваша модель выглядит лучше как структура:

type Person struct {
    ID int
    Name string
}

var people []Person
rows, err := db.Queryx(query)
for rows.Next() {
    var p Person
    err = rows.StructScan(&p)
    if err != nil {
        log.Fatal(err)
    }
    people = append(people, p)
}

Тебе не кажется?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...