Найти записи по крайней мере с одной ассоциацией, но исключить записи, где любые ассоциации соответствуют условию - PullRequest
0 голосов
/ 20 ноября 2018

В следующей настройке у клиента есть много тегов через теги.

class Customer
  has_many :taggings
  has_many :tags, through: :taggings
end

class Tagging
  belongs_to :tag
  belongs_to :customer
end

Запрос, который я пытаюсь выполнить в Rails с postgres, состоит в том, чтобы найти всех клиентов, у которых есть хотя бы один тег, но они неУ него может быть один из тегов A или B.

Необходимо учитывать производительность, поскольку количество клиентов составляет десятки тысяч.

Ответы [ 3 ]

0 голосов
/ 20 ноября 2018

Пусть tag_ids - это массив идентификаторов A и B:

tag_ids = [a.id, b.id]

Затем вам нужно найти клиентов, у которых есть тег A или B:

except_relation = Customer.
  joins(:tags).
  where(tags: { id: tag_ids }).
  distinct

Иисключите их из тех, у которых есть хотя бы один тег:

Customer.
  joins(:tags).
  where.not(id: except_relation).
  distinct

INNER JOIN, созданный .joins, удаляет Customer без тега и является источником ошибок, поэтому необходим distinct.

UPD : когда вам нужна производительность, вам, вероятно, придется изменить схему БД, чтобы избежать дополнительных объединений и индексов.Вы можете искать примеры реализации тегов jsonb.

0 голосов
/ 20 ноября 2018

Пожалуйста, попробуйте следующий запрос.

Customer.distinct.joins(:taggings).where.not(id: Customer.joins(:taggings).where(taggings: {tag_id: [tag_id_a,tag_id_b]}).distinct )

Объяснение.

Объединения запустят запрос внутреннего объединения и обеспечат получение только тех клиентов, которые имеюткак минимум один тег, связанный с ними.

where.not позаботится о вашем дополнительном состоянии.

Надеюсь, это поможет.

0 голосов
/ 20 ноября 2018

Получить идентификаторы тегов A и B

ids_of_tag_a_and_b = [Tag.find_by_title('A').id, Tag.find_by_title('B').id]

Найдите всех клиентов, у которых есть хотя бы один тег, но нет ни одного из тегов A или B.

#Customer.joins(:tags).where.not("tags.id in (?)", ids_of_tag_a_and_b)
Customer.joins(:tags).where.not("tags.id = ? OR tags.id = ?", tag_id_1, tag_id_2)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...