Подтвердить что ты не робот

Запрос Rails 3 при условии подсчета ассоциации

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

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

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

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

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

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

4b9b3361

Ответ 1

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

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

Красота этого заключается в том, что MetaWhere все еще использует ActiveRecord и isl для выполнения запроса, поэтому он работает с "новыми" рельсами 3 способами выполнения запросов.

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

Ответ 2

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

Customer.joins(:purchases).group("customers.id").having("count(purchases.id) > ?",0)

Ответ 3

Это немного более подробный, но если вы хотите, чтобы клиенты 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