2013-04-11 2 views
2

Скажем, у меня есть следующие моделиActiveRecord запроса фильтрации вложенных моделей

Course has_many :students 
Course has_many :lectures 
Lecture has_many :topics 

Если я:

courses = Course.find(:all, :includes => [:students, {:lectures => :topics}]) 

Я получаю все курсы, студенты, лекции и темы.

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

Так скажите, что я хочу получить все курсы со студентом по имени «Джон», но только две самые последние лекции для каждого из этих курсов и все темы для этих двух лекций.

Я не понимаю, как применить эти фильтры к исходному запросу выше.

Хотелось бы узнать, как выполнять такие запросы.

+0

Im используя рельсы 3.2 –

+0

Я рекомендую использовать драгоценный камень «squeel» (https://github.com/ernie/squeel). Он имеет гораздо более «интуитивный» синтаксис, и вы можете найти документацию, которую вы ищете в github. – benams

+0

В каком поле вы хотите определить, является ли лекция «последней»? – PinnyM

ответ

0

Вы должны использовать API запросов, чтобы изменить то, что хочет нагруженный:

courses = Course.includes(:students, {:lectures => :topics}). 
       where(:students => {:name => 'John'}) 

Получение только 2 самых последних лекций для каждого курса является одной из основных проблем, я не считаю, что есть межбазовых решение, которое сделает это без рекурсивного подзапроса, чтобы определить ранг (который был бы серьезным утечкой производительности для нетривиальных объемов данных и отменил бы любую выгоду от нетерпеливой загрузки). Вы можете определить самый последний (MAX), а затем следующий самый последний после этого (MAX, который раньше первоначального MAX), но этот подход также будет довольно неэффективным и очень грязным.

Если вы можете выбрать конкретную СУБД, это может быть выполнимо. Альтернативно, выберите другую стратегию, чтобы определить «недавнюю» (например, кешированную дату на каждом курсе или фиксированное количество времени).

UPDATE

Предполагая, что вы хорошо с просто жадными загрузками всех лекции и вручную выбрать верхние 2, вы можете сделать это (для JSON) с использованием as_json сериалайзера:

courses = ... # same as above 
courses.each do |c| 
    c.lectures = c.lectures.sort_by(&:happens_at)[-1..-2] 
end.as_json(:include => [:students, {:lectures => {:include => :topics}}]) 
+0

Спасибо, если бы я делал этот запрос, чтобы вернуть кадр JSON, как бы я его создал с помощью самых последних лекций. ['code'] Курсы = Course.where (: students => {: name => 'John'}) courses.each do | course | Конечно [: most_recent] = course.lectures.order (: happens_at) .Первый курс [: next_recent] = course.lectures.order (: happens_at) [1] конец [/ 'code'] кажется неудобно, хотя –

+0

@johnsample: обновлено для этого. – PinnyM

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