1

导轨 2.3.4

我搜索了谷歌,并没有找到我的困境的答案。

对于这个讨论,我有两个模型。用户和条目。用户可以有多个条目(每天一个)。

条目具有值和 sent_at 日期。

我想按星期几查询并显示用户条目的平均值。因此,如果用户输入了过去 3 周的值,我想显示周日、周一等的平均值。在 MySQL 中,这很简单:

SELECT DAYOFWEEK(sent_at) as day, AVG(value) as average FROM entries WHERE user_id = ? GROUP BY 1

该查询将返回 0 到 7 条记录,具体取决于用户至少拥有一个条目的天数。

我查看了 find_by_sql,但是在搜索 Entry 时,我不想返回 Entry 对象;相反,我需要最多 7 天和平均值的数组...

另外,我有点担心它的性能,因为我们想在用户登录时将它加载到用户模型中,以便它可以显示在他们的仪表板上。欢迎任何建议/指点。我对 Rails 比较陌生。

4

2 回答 2

2

您可以直接查询数据库,无需使用实际的 ActiveRecord 对象。例如:

ActiveRecord::Base.connection.execute "SELECT DAYOFWEEK(sent_at) as day, AVG(value) as average FROM entries WHERE user_id = #{user.id} GROUP BY DAYOFWEEK(sent_at);"

这将为您提供 MySql::Result 或 MySql2::Result ,然后您可以在此枚举上使用每个或全部来查看结果。

至于缓存,我建议使用 memcached,但任何其他 Rails 缓存策略也可以。memcached 的好处是你可以让你的缓存在一段时间后过期。例如:

结果 = Rails.cache.fetch('user/#{user.id}/averages', :expires_in => 1.day) 做
  # 你的 sql 查询和结果放在这里
结尾

这会将您的结果放入 memcached 中,在“user//averages”键下保存一天。例如,如果您是 id 为 10 的用户,您的平均值将在 memcached 中的 'user/10/average' 下,并且下次您执行此查询时(在同一天内),将使用缓存版本而不是实际命中数据库。

于 2011-02-03T05:54:24.787 回答
0

未经测试,但这样的事情应该可以工作:

@user.entries.select('DAYOFWEEK(sent_at) as day, AVG(value) as average').group('1').all

注意:当您使用select显式指定列时,返回的对象是只读的。Rails 无法可靠地确定哪些列可以修改,哪些列不能修改。在这种情况下,您可能不会尝试修改选定的列,但您也可以通过结果对象修改您的sent_at或列。value

查看ActiveRecord 查询指南,以对新用户友好的格式详细了解此处发生的情况。哦,如果该查询不起作用,请发回,以便其他可能偶然发现此问题的人可以看到(我可能会更新)。


由于entries返回一个数组,这将不起作用,我们可以尝试使用join

User.where(:user_id => params[:id]).joins(:entries).select('...').group('1').all

再说一次,我不知道这是否可行。通常你可以指定whereafter joins,但我还没有看到select组合在那里。这里有一个棘手的问题是,select它可能会完全消除返回任何关于 的数据userfind_by_*避免使用方法以支持在模型中编写一个仅使用( docsEntry )调用您的查询并跳过关联映射的方法可能更有意义。select_all

于 2011-02-03T05:49:45.747 回答