Rails where_exists в сочетании с атрибутами подсчета связанных моделей с двойной глубиной

#ruby-on-rails #activerecord

#ruby-on-rails #activerecord

Вопрос:

У меня есть Filter объект RelevanceLabels , с которым связано has_many . RelevanceLabel Принадлежит an Article .

Я пытаюсь выполнить уродливый запрос: я хочу найти все Filters , у которых есть по крайней мере 10 RelevanceLabels , где у каждого RelevanceLabel Article нет a nil token_vector .

В настоящее время я использую where_exists gem, что упрощает первую часть:

streams_with_labels = Filter.where_exists(:relevance_labels)

Но тогда я все еще прибегаю к уродству в циклах:

     stream = Filter.find(filter_id)

    labels = stream.relevance_labels

    return if labels.length < 10

    labels_with_tokens = labels.reject { |label| label.article.token_vector.nil? }

    return if labels_with_tokens.length < 10

    ...
 

Я уверен, что есть какая-то цепочка-фу, которая просто ускользает от меня, но я даже не уверен, с чего начать.

Ответ №1:

То, что вы, вероятно, хотите сделать здесь, это просто СГРУППИРОВАТЬ filters.id и добавить предложение HAVING, чтобы добавить условие для каждой группы:

 class Filter < ApplicationRecord
  has_many :relevance_labels 
  has_many :articles, through: :relevance_labels 

  def self.with_articles(n = 10)
    joins(:articles)
      .group(:id) # filters.id
      .where.not(articles: { token_vector: nil })
      .having(
        Article.arel_table[Arel.star].count.gte(n)
      )
  end
end
 

Article.arel_table[Arel.star].count.gte(n) это более переносимый способ записи having("COUNT(articles.*) >= ?", ?) .