2013-05-01 3 views
0

Я использую очень базовую функцию анализа для моего приложения Rails. Я хочу предоставить статистику, которая сообщит пользователям, сколько посетителей просмотрели их профиль, а затем также разбить их в соответствии с конкретной ролью (я использую «ролик» в своем приложении) у каждого посетителя.Как уменьшить число похожих запросов

В шоу действии контроллера Users, я делаю это

@profileviews = Profileview.where(:user_id => @user.id) 
@profileviewsbysomerole = Profileview.where({:user_id => @user.id, :viewer_role => 'someRole'}) 
@profileviewsbysomeotherrole = Profileview.where({:user_id => @user.id, :viewer_role => 'someOtherRole'}) 

, а затем в шоу-акции, я бы

Your profile has been viewed <%= @profileviews.size %> times. 
Your profile has been viewed by users with a particular role <%= @profileviewsbysomerole.size %> times. 
Your profile has been viewed by users with some other role <%= @profileviewsbysomeotherrole.size %> times. 

Есть ли способ сделать то, что я m пытается обойтись без трех отдельных запросов, или это лучший способ (с точки зрения не ухудшающейся производительности) получить эти статистические данные.

ответ

1

С точки зрения производительности, я думаю, что все в порядке. Другой вариант - запросить все объекты, а затем фильтровать в памяти, но я не думаю, что это хорошая идея. Лучше всего позволить базе данных делать то, что она делает лучше всего.

Одна вещь, которая приходит на ум - вы можете использовать один запрос и group_by, чтобы избежать второго и третьего вызовов, но это актуально, если вы хотите получить некоторые агрегированные данные.

С точки зрения стиля кодирования вы можете определить области применения для разных запросов и использовать их в представлении, но это может быть излишним.

+0

Согласен, я бы определил некоторые области для этих запросов, но я бы не использовать их взглядов. Это просто сделает код более чистым. –

+0

Спасибо за информацию. Не могли бы вы показать мне, как group_by может избежать второго и третьего звонков? Я понимаю, как это можно использовать в целом, но я не вижу, как это могло бы избежать вызовов. – BrainLikeADullPencil

+0

Например, если вы хотите подсчитать виды для каждой роли, вы можете сделать что-то вроде: Profileviews.select («count (profileviews.id) как num_views, viewer_role as role»). Group ("role") – davidrac

1

Если вы будете использовать эти вещи вместе много, было бы хорошо, чтобы связать их вместе что-то вроде этого:

# in user model 
def profile_view_hash(*roles) 
    views = { 'all' => Profileview.where(:user_id => id).all } 
    roles.each do |role| 
    views.merge!({ 
     role => Profileview.where(:user_id => id, :viewer_role => role).all 
    }) 
    end 
    views 
end 

Это позволит вам использовать его как это:

# in controller 
@profile_views = @user.profile_view_hash('someRole','someOtherRole') 

# in view 
<%= @profile_views['all'] %> 
<%= @profile_views['someRole'] %> 
<%= @profile_views['someOtherRole'] %> 

Кстати, в вашем примере вы показываете только результат .size. Если это все, что вам нужно, вы должны использовать count вместо all

+0

Большое спасибо. Отлично. Что касается вашего последнего комментария, вы говорите, что я должен сделать это в своем контроллере, если все, что мне нужно, это размер (который может быть в некоторых случаях, а не в других): @profileviewsbysomerole = Profileview.where ({: user_id => user. id,: viewer_role => 'somerole'}). count – BrainLikeADullPencil

+0

, добавив счетчик в конце запроса, не позволяет ли Rails извлекать все до подсчета? – BrainLikeADullPencil

+0

@BrainLikeADullPencil Да, использование .count преобразует SQL-запрос в 'select count (*) из profile_views, где yadda yadda..', который будет быстрее, но не будет иметь никаких данных. – Unixmonkey

1

я оставил бы их всех из контроллера, и сделать вид, как это:

Your profile has been viewed <%= @user.profileviews.size %> times. 
Your profile has been viewed by users with a particular role <%= @user.profileviews.select { |profile_view| profile_view.viewer_role == 'someRole' }.size %> times. 
Your profile has been viewed by users with some other role <%= @user.profileviews.select { |profile_view| profile_view.viewer_role == 'someOtherRole' }.size %> times. 

Вы можете взять это еще дальше, переместив эта логика в Profileview, может понравиться:

def views_for_role(role) 
    select { |profile_view| profile_view.viewer_role == role }.size 
end 

и делегировании его в User, может быть, как:

delegate :views_for_role, :to => :profileview 

Что бы сделать ваш взгляд выглядеть следующим образом:

Your profile has been viewed <%= @user.profileviews.size %> times. 
Your profile has been viewed by users with a particular role <%= @user.views_for_role 'someRole' %> times. 
Your profile has been viewed by users with some other role <%= @user.views_for_role 'someOtherRole' %> times. 
+0

Спасибо, что показал мне это. Я буду играть с ним и подумать над его использованием. – BrainLikeADullPencil

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