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

Sha*_*nak 1 timestamp ruby-on-rails

背景

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

我还有另一个表历史记录,它转储了每个传感器收到的所有传感器值.

因此关系是 "传感器有很多历史",time_stamp col记录创建时间戳.

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

问题

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

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

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

谢谢Shaunak

Ben*_*Lee 8

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

sensor.histories.order("ABS(time_stamp - #{params[:time_stamp].to_i})").first
Run Code Online (Sandbox Code Playgroud)

请注意,对于此查询,我假设您使用的是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
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)