2013-08-30 2 views
0

Я работаю над функцией поиска элементов.Eager Загрузка только первой страницы результатов с активной записью

Моя модель это, roughtly:

User has many items 
User has many addresses 
User has one profile 
Item has many images 
Item has many addresses 
Item belongs to category 

Я хочу, чтобы отобразить результаты, сгруппированные пользователем, например:

Results for 'Laptop': 

Items of Bob: 
    Laptop dell (details...) 
    Samsung laptop (details...) 

Items of Alice: 
    Laptop HP (details...) 
... 

Так что у меня этот большой запрос с жадным загрузки:

r = User.includes([{items: [:images, :addresses, :category]}, :addresses, :profile]). 
    joins(:items). 
    where('query like "%laptop%"'). 
    where(...). 
    limit(80). 
    all 
# then get the first page of results with kaminary 

И затем я показываю с такой петлей в erb:

r.each do |u| 
    # items of user u 
    u.items do |i| 
    # item i 
    end 
end 

Все работает нормально, за исключением того, что интенсивная загрузка занимает некоторое время. Это может быть намного быстрее, если вы загрузите только элементы на первой странице, которые отображаются.

Возможно с активной записью, чтобы загружать только записи с условием? Что-то вроде: User.includes([:table1, table2], conditions: 'users.id in (1,2,3)')?

Другим решением было бы выполнить большой запрос с ограничением 20, а затем повторить запрос без активной загрузки с лимитом 80, а затем вручную объединить результаты, но это сложно?

Любые другие предложения?

ответ

0

Я закончил работу с двумя запросами и объединил результаты. Это не так сложно, как это звучит:

# per_page is 20 
limit = "#{(page.to_i - 1) * 20}, #{(page.to_i * 20)}" 
query = Users.where('items.title LIKE "%whatever%"').where('addresses.lat < 50') 
return query.includes([{items: [:images, :category]}, :profile, :addresses]). 
    joins(:items).   
    limit(limit).all | 
    query.select('DISTINCT users.*').joins(:items, :addresses). 
    limit(200).all 

Примечания 1:

этих жаждущих нагрузок только 20 элементов текущей страницы, и добавляет все элементы на других страницах без нетерпеливой загрузки. Например, скажем, что вы находитесь на стр. 3, первый запрос будет загружать с limit 60, 80 и добавлять элементы от # 0 до # 199. Способ объединения массива (оператор |) работает в ruby ​​- это то, что если один и тот же элемент присутствует в обоих массивах, элемент в первом массиве сохраняется. В этом случае элемент в первом массиве будет загружать элемент. Поэтому, если мы находимся на третьей странице, он объединит [60..80] (eager loaded) с [1..200] (not eager loaded), а элементы 60 - 80 в последнем массиве будут теми, что были в первом массиве.

Примечание 2:

Выбор: отчетливый важно, потому что без него предел будет ограничение на количество элементов или адресов. Например, если пользователь # 1 имеет 198 объектов, то второй запрос будет возвращать что-то вроде этого:

user 1 - item 1 of user 1 
    user 1 - item 2 of user 1 
    ... 
    user 1 - item 198 of user 1 
    user 2 - item 1 of user 2 
    user 3 - item 1 of user 3 

И это не правильно поджать. У нас были бы пользователи [1, 2, 3, 60, 61, ... 80] после слияния.

С отчетливый, результаты были бы:

user 1 - item 1 of user 1 
    user 2 - item 1 of user 2 
    user 3 - item 1 of user 3 
    ... 
    user 200 - item 1 of user 200 

И мы бы [1, 2, 3 ... 200] после слияния, с элементами 60 до 80, взятых из первого запроса.

Примечание 3:

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