Как найти записи по «количеству» ассоциаций, используя рельсы и монгоиды? - PullRequest
8 голосов
/ 22 ноября 2011

С этими моделями:

class Week
  has_many :proofs
end
class Proof
  belongs_to :week
end

Я хочу сделать что-то вроде:

Week.where(:proof.count.gt => 0)

Чтобы найти только недели, которые имеют несколько доказательств.

Существует один ответ, который, кажется, касается этого:

Может ли фильтр областей рельсов по количеству связанных классов для данного поля

Но в этом примере в Week отсутствует такой атрибут, как proof_ids, поскольку идентификаторы хранятся вместе с доказательствами. Это не работает, например:

Week.where(:proof_ids.gt => 0)

Как этот запрос возможен? Концептуально просто, но я не могу понять, как это сделать с монго или монгоидом.

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

Week.desc(:proofs.size)

Но это тоже не работает.

Я понимаю, что встречный кеш - это вариант для моих конкретных вопросов, но я также хотел бы иметь возможность выполнить запрос.

Заранее спасибо за любую помощь.

Ответы [ 3 ]

5 голосов
/ 22 ноября 2011

С рельсами (и без counter_cache) вы можете сделать:

class Week < ActiveRecord::Base
  has_many :proofs

  def self.by_proofs_size
    sort_by { |week| week.proofs.size }
  end

  def self.with_at_least_n_proofs(n = 1)
    select { |week| week.proofs.size >= n }
  end
end

Хотя каждая из этих операций создает 2 запроса, это далеко от идеала.

Пара запросов повторяется (=> 4 запроса для каждой операции) с областями действия (ошибка?):

scope :with_at_least_n_proofs, -> (n = 1) { select { |w| w.proofs.size >= n } }
scope :by_proofs_size, -> { sort_by { |w| w.proofs.size } }

Идеально, вероятно, использовать counter_cache

scope :with_at_least_n_proofs, -> (n = 1) { where('proofs_count >= ?', n) }
scope :by_proofs_size, -> { order(proofs_count: :desc) }
4 голосов
/ 03 мая 2012

Я не знаю, является ли это лучшим решением, поскольку оно отображает его через массив, но это делает свою работу: (другие решения, упомянутые здесь, дают мне исключения)

class Week < ActiveRecord::Base

  scope :has_proofs, -> { any_in(:_id => includes(:proofs).select{ |w| w.proofs.size > 0 }.map{ |r| r.id }) }

end
0 голосов
/ 22 ноября 2011

Прошу прощения, если я далеко - но вы могли бы использовать простой counter_cache в таблице недель? Тогда вы можете сделать что-то вроде week.proofs_count.

...