2016-02-03 3 views
1

У меня есть следующая проблема. Мне нужно сделать массивный запрос таблиц с именами профессионалов, но мне нужно оптимизировать запрос, потому что для каждого профессионала я вызываю связанные таблицы.Запросы с включенными в Rails

Но у меня есть проблема с двумя связанными таблицами: комментариями и тарифами.

Комментарии:

Мне нужно позвонить 3 комментария для каждого профессионала. Стараюсь с:

@professionals.includes(:comments).where(:comments => { type: 0 }).last(3) 

Проблема запроса только приносит 3 профессионалов, а не то, что мне нужно, все профессионалы, которые имеют только три замечания типа, где быть равны нулю.

И когда я пытаюсь:

@professionals.includes(:comments).where(:comments => { type: 0 }) 

В результате только профессионалы (все) комментарии, когда мне нужно все профессиональные или без комментариев. Но если профессионал есть комментарии мне нужно только три последние комментарии, где быть типа равна нулю

Тарифы:

С тарифами У меня аналогичная проблема, в этом случае мне нужно 4 последние тарифы для каждого профессионал. Я стараюсь:

@professionals.includes(:tariffs).last(4) 

Но только последние 4 профессионалов.

Модели:

class Comment < ActiveRecord::Base 
     belongs_to :client 
     belongs_to :professional 

end 

class Professionals < ActiveRecord::Base 
     has_many :comment 

end 
+0

У меня нет проблем с вашим вторым вариантом. Вы включаете все соответствующие комментарии для всех профессионалов, что хорошо. Если вы хотите получить последние 3 для отдельного профессионала, вы можете вызвать professional.comments.limit (3) или professional.last (3), когда вы зацикливаете профессионалов в своем запросе. Первый возвращает ActiveRecord :: Relation, а один из них - Array. Можете ли вы показать, где вы хотите использовать последние 3 комментария на одного профессионала? –

+0

Вам нужно будет запустить подзапрос в предложении 'WHERE', которое подсчитывает количество комментариев. Однако как это сделать (и что более важно, как это сделать, не убивая производительность), зависит от того, какую RBDMS вы используете. '.last (3)' не работает, поскольку он применяет 'LIMIT' для всего запроса. – max

ответ

2

Вы не можете использовать ограничение на присоединение таблицы в ActiveRecord. limit применяется к первому отношению, которое в этом случае имеет значение @professionals.

У вас есть несколько вариантов выбор:

  1. преднагрузки все комментарии для каждого специалиста и ограничить их на выходе (уменьшает количество запросов, необходимых, но увеличивает потребление памяти, поскольку вы потенциально предварительную загрузку много объектов AR) ,
  2. Lazy загружает требуемое количество комментариев (увеличивает количество запросов на n + 1, но уменьшает потребление потенциальной памяти).
  3. Напишите пользовательский запрос с необработанным SQL.

Если вы предварительно загрузите все, то вам не придется много менять. Просто ограничьте количество комментариев белым, повторяя каждый @professional.

@professionals.each do |professional| 
    @professional.comments.limit(3) 
end 

Если вы ленивы нагрузки только то, что вам нужно, то вы бы применить limit простор для комментариев отношения.

@professionals.all 
@professionals.each do |professional| 
    @professional.comments.where(type: 0).limit(3) 
end 

Написание пользовательского запроса немного сложнее.Но вы можете обнаружить, что это может быть менее результативным в зависимости от количества объединений, которые вы должны выполнить, и насколько хорошо проиндексирована ваша таблица.

Предлагаю вам воспользоваться двумя подходами и использовать кеширование запросов и фрагментов для повышения производительности. Например:

- cache @professionals do 
    - @professionals.each do |professional| 
    - cache professional do 
     = professional.name 

Этот подход ударит к базе данных в первый раз, но после последующих нагрузок комментарии будут прочитаны из кэша, избегая попадания DB. Подробнее о кешировании читайте в Rails Guides.

+0

спасибо, что работает –

Смежные вопросы