Запрос Rails 3 при условии подсчета ассоциации - PullRequest
31 голосов
/ 11 июня 2011

В Rails 3 с mysql, предположим, у меня есть две модели, Клиенты и Покупки, очевидно, что покупка принадлежит клиенту.Я хочу найти всех клиентов с 2 или более заказов.Я могу просто сказать:

Customer.includes(:purchases).all.select{|c| c.purchases.count > 2}

Фактически, приведенная выше строка делает запрос о величине Customer.all и Purchase.all, затем выполняет обработку типа "select" в ruby.В большой базе данных я бы предпочел не делать все эти вычисления «select» в ruby, а mysql выполняет обработку и предоставляет мне только список квалифицированных клиентов.Это намного быстрее (поскольку mysql более настроен на это) и значительно уменьшает пропускную способность базы данных.

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

Customer.joins(:purchases).where("count(purchases) > 2").all

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

Ответы [ 3 ]

73 голосов
/ 21 февраля 2012

Нет необходимости устанавливать драгоценный камень, чтобы заставить его работать (хотя мета где-то круто)

Customer.joins(:purchases).group("customers.id").having("count(purchases.id) > ?",0)
9 голосов
/ 11 июня 2011

Документация по этому материалу довольно скудна на данный момент.Я хотел бы использовать Metawhere , если вы будете делать больше запросов, похожих на это.Используя Metawhere, вы можете сделать это (или что-то подобное, не уверенный, если синтаксис точно правильный):

Customer.includes(:purchases).where(:purchases => {:count.gte => 2})

Прелесть этого в том, что MetaWhere все еще использует ActiveRecord и arel для выполнения запроса, поэтомуработает с 'новыми' rails 3 способами выполнения запросов.

Кроме того, вы, вероятно, не хотите вызывать .all в конце, так как это приведет к тому, что запрос пингует базу данных.Вместо этого вы хотите использовать отложенную загрузку и не нажимать на базу данных, пока вам не потребуются данные (в представлении или каким-либо другим способом, который обрабатывает фактические данные).

0 голосов
/ 05 января 2016

Это немного более многословно, но если вы хотите, чтобы клиенты where count = 0 или более гибкий SQL, вы бы сделали LEFT JOIN

Customer.joins('LEFT JOIN purchases on purchases.customer_id = customers.id').group('customers.id').having('count(purchases.id) = 0').length
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...