按周/月/等和 ActiveRecord 分组?
Posted
技术标签:
【中文标题】按周/月/等和 ActiveRecord 分组?【英文标题】:Grouping by week/month/etc & ActiveRecord? 【发布时间】:2010-10-28 12:39:35 【问题描述】:我正在我的产品中进行一些静态计算。用户执行了许多操作,比如说发布的 cmets。我希望能够向他们展示他们在过去一个月中每周发布了多少 cmets,或者在过去一年中每月发布了多少 cmets。
activerecord 有什么办法可以这样分组吗?我最好的办法是简单地手动执行此操作 - 根据我自己的标准迭代记录总和吗?
class User < ActiveRecord::Base
has_many :comments
end
class Comments < ActiveRecord::Base
belongs_to :user
end
@user.comments(:all).map |c| ...do my calculations here...
或者有更好的方法吗?
谢谢! 奥伦
【问题讨论】:
【参考方案1】:在这种情况下,对我来说最好的解决方案是直接使用 SQL,或者使用 Ruby group_by 函数:
@user.all.group_by |u| u.created_at.beginning_of_month
【讨论】:
group_by
不是 ActiveRecord 方法,而是Enumerable
上的 Ruby 方法。
只使用u.created_at.month
会更短
请注意,这会从数据库中加载所有记录,实例化 ActiveRecord 对象,将日期解析为 ActiveSupport 的时区感知对象——所有这些都只是为了计算记录数。
这是一种不好的做法,因为当您使用 .all 时,它会获取数据库中的所有记录,这将花费您太多
多么浪费内存!使用@WojtekKruszewski 解决方案:@user.comments.group("DATE_TRUNC('month', created_at)").count
【参考方案2】:
查看团体日期宝石
https://github.com/ankane/groupdate
它具有最近的提交,与 postgresql 一起使用,与 chart kick 轻松集成以实现快速图表,并且与时区一起使用!!
【讨论】:
GroupDate 仅适用于 UTC,因此如果您在数据库中使用其他时区,请考虑替代方案。【参考方案3】:使用 group_by
@user.comments.group_by(&:week)
class User < ActiveRecord::Base
def week
some_attribute_like_date.strftime('%Y-%W')
end
end
这将为您提供格式为 YYYY-WW 的分组列表
【讨论】:
【参考方案4】:这是更精致的版本
@user.comments.group("year(created_at)").group("month(created_at)").count
【讨论】:
【参考方案5】:我的猜测是这样的:
@user.comments.count(:group => "year(created_at),month(created_at)")
干码,ymmv
【讨论】:
我相信这也会按月分组 - 所以如果你有两年的数据,所有的东西都在第 1 年和第 2 年 1 月。我正在寻找的是一种方法例如,告诉一个 24 个月的窗口,每月有多少。 您也可以添加一个条件来限制年份,例如 :conditions => [:created_at, "> #24.months.ago"]。同样,未经测试,但应该可以使用这样的东西。 这似乎是 mysql 特有的【参考方案6】:在 Postgres 中你可以这样做:
@user.comments.group("DATE_TRUNC('month', created_at)").count
得到:
"2012-08-01 00:00:00"=>152, "2012-07-01 00:00:00"=>57, "2012-09-01 00:00:00"=>132
它接受从“微秒”到“千年”的值进行分组: http://www.postgresql.org/docs/8.1/static/functions-datetime.html#FUNCTIONS-DATETIME-TRUNC
【讨论】:
比使用 ruby 可枚举 group_by 快得多! Wojtek,如果一个月内什么都没有创建呢?那个月你什么也得不到。 @MattSmith 我相信是的。幸运的是,从该查询的输出中读取值时提供默认值很容易:output.fetch("2012-08-01 00:00:00", 0)
在我的例子中,键是 Ruby Time 对象,所以我可以使用result[Time.current.utc.beginning_of_month]
访问结果。不知道为什么答案会显示带有字符串键的结果,或者多年来是否发生了变化。
有排序吗?哈哈,钥匙坏了【参考方案7】:
查看 has_activity 插件。
【讨论】:
感谢您的指点。看起来 has_activity 只是 mysql 。我的生产主机是 postgresql。以上是关于按周/月/等和 ActiveRecord 分组?的主要内容,如果未能解决你的问题,请参考以下文章
Oracle里面如何让一段日期按周、月、季度、年分组显示啊?求高手赐教,贴出正确sql追加高分!