GORM: фильтрация сущности по связанной сущности

30 марта 2020 г. Gorm Sql Postgresql


Эта задача не так проста, особенно с GORM.

Посмотрите на следующие сущности:

type Parent struct {
gorm.Model
Name string
}

type Child struct {
gorm.Model
ParentID uint // связь child -> parent многие к одному
Name     string
}

В коде используется gorm.Model для базовой структуры.

Как отфильтровать родителей, фильтруя связанных детей?

Общее решение в SQL-базах данных — использовать простой JOIN и затем фильтровать. Это возможно с GORM:

err := db.Model(&Parent{}).Joins(
"LEFT JOIN children ON parents.id = children.parent_id AND children.name = ?",
"somename",
).Find(&results).Error

Полный запрос:

SELECT * FROM "parents" LEFT JOIN children ON parents.id = children.parent_id AND children.name = 'somename'

Но это обычно не работает для нашей задачи — для родителей, у которых несколько совпадающих детей. В этом случае у нас будут такие родители повторяться несколько раз.

Таким образом, простой JOIN здесь, вероятно, не работает. Нам, вероятно, нужно решение на основе условия WHERE. Следующий код работает отлично:

err := db.Model(&Parent{}).Where(
"EXISTS (SELECT 1 FROM children WHERE children.parent_id = parents.id AND children.name = ?)",
"somename",
).Find(&results).Error

Полный запрос выглядит следующим образом:

SELECT * FROM "parents" WHERE EXISTS (SELECT 1 FROM children WHERE children.parent_id = parents.id AND children.name = 'somename')
Tags:

Проверьте свои знания

1. Почему простой JOIN не работает для фильтрации родителей по связанным детям, когда у родителей несколько совпадающих детей?
2. Какое решение рекомендуется для фильтрации сущностей по связанным сущностям в GORM?
3. Что возвращает подзапрос EXISTS?

Похожие статьи

7 апреля 2020 г.

Фильтрация по списку значений с помощью GORM

Когда необходимо отфильтровать данные по списку значений (например, по ID: 1, 2, 3), следует использовать оператор ANY в сочетании с pq.Array из драйвера PostgreSQL.

Read More → Gorm Sql Postgresql