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
}

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

Общее решение в 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: