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

30.03.2020 gorm sql postgresql


Представим себе такую структуру сущностей:

type Parent struct {
	gorm.Model
	Name string
}

type Child struct {
	gorm.Model
	ParentID uint // child -> parent many to one link
	Name     string
}

Как теперь отфильтровать родителей по наличию связанных детей с определенными признаками?

В первую очередь мы думаем о 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).

Следовательно, решение должно быть без JOIN, желательно добавить только where. Cледующий фрагмент работает:

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')

Другие статьи