sqlx сканирует массив postgres в структуру - PullRequest
0 голосов
/ 04 января 2019

Я пытаюсь создать базовый API для комментирования в go.Я не могу понять, как сканировать массивы postgresql в массив структур внутри структуры.Я думаю, что я мог бы, вероятно, иметь тип Thread.Posts быть jsonb, но это кажется не элегантным, так как я должен разобрать его, я думаю.

sql: Ошибка сканирования индекса столбца 3, имя «posts»: unsupportedСканирование, сохранение драйвера. Тип значения [] uint8 в модели типа * []. Почтовый индекс

var threadSchema = `
CREATE TABLE IF NOT EXISTS thread (
  id         SERIAL PRIMARY KEY,
  name       VARCHAR(100) NOT NULL,
  profile_id INTEGER REFERENCES profile (id)
)`

var postSchema = `
CREATE TABLE IF NOT EXISTS post (
  id         SERIAL PRIMARY KEY,
  comment    TEXT,
  profile_id INTEGER REFERENCES profile (id),
  thread_id  INTEGER REFERENCES thread (id)
)`

type Post struct {
    Id        int    `db:"id" json:"id"`
    Comment   string `db:"comment" json:"comment" binding:"required" form:"comment"`
    ProfileId int   `db:"profile_id" json:"profile_id" binding:"required" form:"profile_id"`
    ThreadId  int    `db:"thread_id" json:"thread_id" binding:"required" form:"thread_id"`
}

type Thread struct {
    Id        int    `db:"id" json:"id"`
    Name      string `db:"name" json:"name" binding:"required" form:"name"`
    ProfileId int    `db:"profile_id" json:"profile_id" binding:"required" form:"profile_id"`
    Posts     []Post `db:"posts" json:"posts" form:"posts"`
}

func GetThreads(db *sqlx.DB, c *gin.Context) {
    threads := []Thread{}
    err := db.Select(&threads, `
    SELECT thread.id,thread.name,thread.profile_id,array_agg(post.id) AS posts
    FROM thread
    INNER JOIN post ON thread.id = post.thread_id
    GROUP BY thread.id;
  `)
    if err != nil {
        log.Fatal(err)
    }
    c.JSON(http.StatusOK, gin.H{"data": threads})
}

1 Ответ

0 голосов
/ 04 января 2019

Во-первых, вы не можете сделать это с sqlx , независимо от того, используете вы массивы Postgres или нет.

Во-вторых, ваш SQL-запрос просто объединяет идентификаторы Post, а несодержание сообщений, поэтому нет способа получить нужные данные (используя Go или иным образом).

Итак, вот что вы можете сделать:

  1. Использовать анонимноговстроенная структура, захватывает весь контент Post в вашем запросе SQL, а затем объединяет ваши дублированные потоки.

    type Post struct {
        Id        int    `db:"id" json:"id"`
        Comment   string `db:"comment" json:"comment" binding:"required" form:"comment"`
        ProfileId int   `db:"profile_id" json:"profile_id" binding:"required" form:"profile_id"`
        ThreadId  int    `db:"thread_id" json:"thread_id" binding:"required" form:"thread_id"`
    }
    
    type ThreadDb struct {
        Id        int    `db:"id" json:"id"`
        Name      string `db:"name" json:"name" binding:"required" form:"name"`
        ProfileId int    `db:"profile_id" json:"profile_id" binding:"required" form:"profile_id"`
        Post
    }
    
    type Thread struct {
        Id        int    `db:"id" json:"id"`
        Name      string `db:"name" json:"name" binding:"required" form:"name"`
        ProfileId int    `db:"profile_id" json:"profile_id" binding:"required" form:"profile_id"`
        Posts     []Post `db:"posts" json:"posts" form:"posts"`
    }
    
    
    func GetThreads(db *sqlx.DB, c *gin.Context) {
        threads := []ThreadDb{}
        err := db.Select(&threads, `
        SELECT thread.id,thread.name,thread.profile_id,post.id,post.comment,post.profile_id,post.thread_id
        FROM thread
        INNER JOIN post ON thread.id = post.thread_id
        GROUP BY post.id;
      `)
    
        thread_map := make(map[string]Thread)
    
        for i, thread := range threads {
            if _, ok := thread_map[thread.Id]; ok {
                thread_map[thread.Id].Posts = append(thread_map[thread.Id].Posts, thread.Post)
            } else {
                thread_map[thread.Id] = Thread{thread.Id, thread.Name, thread.ProfileId, []Post{thread.Post}}
            }
        }
    
        var threadSlice []string
    
        for k := range thread_map {
            threadSlice = append(threadSlice, k)
        }
    
        if err != nil {
            log.Fatal(err)
        }
        c.JSON(http.StatusOK, gin.H{"data": threadSlice})
    }
    
  2. Используйте GROUP_CONCAT или аналогичный.Я бы не советовал, если вы планируете иметь не более 100 сообщений в теме.
...