在轨道上的红宝石中找到最接近给定时间的记录

时间:2012-01-30 22:55:38

标签: ruby-on-rails timestamp

  

背景

我有一个ror应用程序,它不断记录并在网站上显示实时传感器数据。然后我有一个名为 sensors 的表,它有唯一的所有传感器列表并存储最新值。

我还有另一个表历史,它会转储每个传感器收到的所有传感器值。

因此关系是 “传感器有很多历史记录” time_stamp col记录创建时间戳。

并非所有传感器都以相同的间隔或频率更新。

  

问题

现在我想从用户那里获取输入时间戳,过去的日期和时间,并显示传感器当时显示的内容。例如,我想看看昨天下午2点所有传感器的样子,一旦我有来自用户的时间戳,我如何从历史表中检索最接近输入时间戳的一个传感器值。

我希望在Sensor模型中添加一个方法,该方法将time_stamp作为参数,并从历史记录表中检索最接近输入time_stamp的值。

编写此Active记录查询的最简单方法是什么?

由于 Shaunak

1 个答案:

答案 0 :(得分:8)

只需根据传递的时间戳和历史时间戳之间的差异对历史进行排序(绝对值,使其可以向任一方向),并返回最高结果(即差异最小的结果)。

sensor.histories.order("ABS(time_stamp - #{params[:time_stamp].to_i})").first

请注意,对于此查询,我假设您使用的是MySQL(因为我使用的是MySQL方法ABS),我还假设time_stamp字段存储为unix时间戳,用户输入也是如此。如果数据库存储或输入采用不同的格式,则必须使用不同的日期算术函数。有关详细信息,请参阅http://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html。或者,如果您不使用MySQL,请参阅您正在使用的数据库的文档。

另请注意,我使用.to_i来清理查询的数据。如果您的数据格式不同,则可能需要以不同的方式对其进行清理。

为了提高效率,请将其限制在最大可能范围内的time_spans。如果传感器每10分钟或更频繁地采集数据(读数间距离不小于10分钟),则每侧的距离大于10分钟。像下面的东西。这里,600 = 10(分钟)* 60(秒):

sensor.histories.where("time_stamp >= ? AND time_stamp <= ?", params[:time_stamp].to_i - 600, params[:time_stamp].to_i + 600).order("ABS(time_stamp - #{params[:time_stamp].to_i})").first

将其转换为模型方法很简单:

class Sensor < ActiveRecord::Base
    def history_at(time_stamp)
        self.histories.where("time_stamp >= ? AND time_stamp <= ?", time_stamp.to_i - 600, time_stamp.to_i + 600).order("ABS(time_stamp - #{time_stamp.to_i})").first
    end
end