【问题标题】:Grouping by week/month/etc & ActiveRecord?按周/月/等和 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...}

或者有更好的方法吗?

谢谢! 奥伦

【问题讨论】:

    标签: ruby-on-rails activerecord grouping


    【解决方案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。
        猜你喜欢
        • 1970-01-01
        • 2016-05-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-03-25
        • 1970-01-01
        相关资源
        最近更新 更多