在Rails 3.2应用程序中,我正在尝试构建一个返回具有两个计算计数的数组的查询。该应用程序有三个模型:一个用户有很多事件,一个位置有很多事件。我需要为用户返回一个数组,其中包含每个位置的事件数以及活动事件数。
例如,[#<Location id: 1, name: "Location Name", total_events_count: 4, active_event_count: 4>]>
我可以获得total_event_count
user = User.find(params[:id])
user.locations
.select("locations.id, locations.name, count(events.id) AS total_events_count")
.joins(:events)
.group("locations.id")
鉴于我的Event模型有一个字符串status
字段可以取值active
,我如何在此查询中包含active_events_count?
修改
在xdazz和mu提出一些有用的建议后,我仍然在努力解决这个问题。我的问题似乎是计数正在计算所有事件,而不是属于该位置和用户的事件。
我将尝试重新解释我的问题,希望有人可以帮助我理解这一点。
事件属于用户和位置(即User has_many :locations, through: :events
)
事件包含多个字段,包括status
(字符串)和participants
(整数)。
在用户节目视图中,我正在尝试生成用户位置列表。对于每个位置,我想显示“成功率”。成功率是用户的总数;与参与者的事件除以用户事件的总数。即,如果User1在LocationA有4个事件,但只有其中两个事件有参与者,则User1在LocationA的成功率为0.5(或50%)。
我实现这一目标的方法是通过一个选择查询,该查询还包括total_events_count
和successful_events_count
的计算计数。 (可能有更好的方法吗?)
所以我做了类似的事情:
user = User.find(params[:id])
user.locations
.select("locations.id, locations.name, count(events.id) AS total_events_count, sum(case events.marked when NOT 0 then 1 else 0 end) AS successful_events_count")
.joins(:events)
.group("locations.id")
这将返回一个具有正确键的数组,但值不正确。我获取该位置的所有事件(以及所有成功事件)的总数,而不仅仅是属于当前用户的那些事件的计数。
我一直在关注这个问题,以至于让自己感到非常困惑。非常感谢新的观点和想法!!
EDIT2
在休息和新鲜的眼睛之后,我已经设法使用以下代码获得我需要的结果。这看起来很复杂。如果有更好的方法,请告诉我。否则我会整理这个问题,以防其他人遇到同样的问题。
class User
def location_ratings
events = self.events
successful_events = events.where('events.participants > 0')
user_events_by_location = Event.
select("events.location_id AS l_id, count(events.id) AS location_event_count").
where( id: events.pluck(:id) ).
group("l_id").
to_sql
user_successful_events_by_location = Event.
select("events.location_id AS l_id, count(events.id) AS location_successful_events_count").
where( id: successful_events.pluck(:id) ).
group("l_id").
to_sql
Location.
joins("JOIN (#{user_events_by_location}) AS user_events ON user_events.l_id = location.id").
joins("JOIN (#{user_successful_events_by_location}) AS successful_user_events ON successful_user_events.l_id = location.id").
select('location.id, location.name, user_events.location_events_count, successful_user_events.location_successful_events_count').
order("user_events.location_events_count DESC")
end
答案 0 :(得分:2)
您可以使用sum(events.marked='active')
来获取它:
user.locations
.select("locations.id, locations.name, count(events.id) AS total_events_count, sum(events.marked='active') AS marked_event_count")
.joins(:events)
.group("locations.id")
<强> 更新 强>
如果您使用的是postgresql,那么在使用SUM
函数之前必须将boolean设置为int。
user.locations
.select("locations.id, locations.name, count(events.id) AS total_events_count, sum((events.marked='active')::int) AS marked_event_count")
.joins(:events)
.group("locations.id")