Я пытаюсь переключить реализацию API, над которой я работал, с библиотеки GORM ORM на SQLx, чтобы сделать доступ к данным более эффективным. В частности, я пытаюсь избавиться от некоторых проблем с SELECT N + 1. Итак, у меня есть отношения "один ко многим", когда на сайте есть сообщения. Реализуемый мной API возвращает список сайтов в виде объекта JSON, и каждый сайт имеет вложенный список posts
. Структура выглядит примерно так
{ "sites": [ { "id": 1, "name": "Site #1", "posts" [ {"title": "Post #1", "published": "1/2/2000", ... }, {"title": "Post #2", "published": "1/3/2000", ... }, ... more posts ... ] }, { "id": 2, "name": "Site #2", "posts": [ ... post list for site #2 ... ] } ... more sites ... ] }
Это было легко реализовать в GORM, но как только я взглянул на SQL GORM, работающий для реализации этого, я понял, что он выполняет SELECT из сообщений для каждого сайта в списке. Поэтому я пытаюсь использовать такой SQL, чтобы избежать проблемы N + 1.
SELECT s.id, s.name, p.title, p.published FROM sites as s, posts as p WHERE p.site_id = s.id
Это дает мне все необходимые данные одним запросом. Но я несколько застрял в том, как отсканировать все это в список структур сайта. В GORM у меня были определены следующие структуры (упрощенные для краткости)
type struct Post { Id uint `json:"-"` Title string Published time.Time SiteId uint `json:"-"` Site Site `json:"-"` } type struct Site { Id uint Name string }
А потом я бы сделал что-нибудь вроде
var sites []Site result := db.Preload('Posts').Find(&sites) if result.Error != nil { ... error handling ... } else { operate on sites here }
Итак, вопрос в том, как мне сканировать мой новый SQL с помощью SQLx на фрагмент структур таким образом, чтобы в результате получилась структура данных, аналогичная той, что создавала GORM? Я не против написать свой собственный сканер, но все же хочу иметь возможность использовать методы SQLx Select()
и Get()
. Что мне нужно сделать, чтобы это сработало?
var sites []Site err := db.Select(query, &sites) // where query is SQL from above
Изменить: кажется, что если я использую точный код, представленный в этом вопросе, GORM на самом деле не выполняет N + 1 выборок, он выполняет два запроса: один простой SELECT для сайтов и один SELECT .. . WHERE ... IN ... для сообщений, а затем сопоставляет два набора результатов. Я все еще хочу знать, как это сделать в SQLx.