go сканирование Postgres array_agg - PullRequest
1 голос
/ 09 апреля 2020

У меня есть отношение «один ко многим» в postgres (у Event есть много EventUser), и я хотел бы отсканировать и сохранить в структуру Event.

// EventUser struct
type EventUser struct {
    ID              int64
    CheckedIn       bool
    PaidAmount      float32
}

// Event struct
type Event struct {
    ID         int64  `json:"id"`
    Name       string `json:"name"`
    StartTime  string `json:"startTime"`
    EventUsers string
}

Вот запрос :

SELECT events.id, events.name, events."startTime", e."eventUsers" as "eventUsers"
FROM "Events" as events
LEFT JOIN (
        SELECT events.id as id, array_to_json(array_agg(eu.*)) as "eventUsers"
        FROM "EventUsers" as eu
        JOIN "Events" AS "events" ON events.id = eu."eventId"
        WHERE eu.status = 'RESERVED'
        GROUP BY events.id
    ) AS e USING (id)
WHERE events.status = 'COMPLETED' 

Запрос возвращает это:

{
  id: 2,
  name: "2 Events are 48 days from now",
  startTime: 1590471343345,
  eventUsers: [
    {
      id: 2,
      checkedIn: false,
      paidAmount: 8
    },
    {
      id: 3,
      checkedIn: false, 
      paidAmount: 8,
    },
  ],
};

Это то, что я пытаюсь сделать, который непосредственно сканирует каждый элемент в eventUsers в структуру и сохраняет в Event. Struct.

got := []Event{}

for rows.Next() {
    var r Event
    err = rows.Scan(&r.ID, &r.Name, &r.StartTime, &r.EventUsers)
    if err != nil {
        panic(err)
    }
}

Я думаю, я мог бы добиться этого, сохранив массив в виде строки, а затем unmarshal it.

То, что я хочу, похоже на sql.NullString.

1 Ответ

1 голос
/ 09 апреля 2020

Вы можете определить тип среза, который реализует интерфейс sql.Scanner. Обратите внимание, что когда вы передаете экземпляр типа, который реализует Scanner, в вызов (*sql.Rows).Scan или (*sql.Row).Scan, метод импелментатора Scan будет вызван автоматически.

type EventUserList []*EventUser

func (list *EventUserList) Scan(src interface{}) error {
    if data, ok := src.([]byte); ok && len(data) > 0 {
        if err := json.Unmarshal(data, list); err != nil {
            return err
        }
    }
    return nil
}

Затем, предполагая, что e."eventUsers" в запросе выбора представляет собой json массив , вы можете использовать его следующим образом:

// EventUser struct
type EventUser struct {
    ID         int64
    CheckedIn  bool
    PaidAmount float32
}

// Event struct
type Event struct {
    ID         int64         `json:"id"`
    Name       string        `json:"name"`
    StartTime  string        `json:"startTime"`
    EventUsers EventUserList `json:"eventUsers"`
}

// ...

var events []*Event
for rows.Next() {
    e := new(Event)
    if err := rows.Scan(&e.ID, &e.Name, &e.StartTime, &e.EventUsers); err != nil {
        return err
    }
    events = append(events, e)
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...