Search code examples
ruby-on-railsdateruby-on-rails-5findersubtraction

Rails finder method that finds an entity that is just more than 24 hours away?


I'm using Rails 5 and PostgreSQL 9.5. I have a table with the following columns .

cindex=# \d crypto_index_values;
                                     Table "public.crypto_index_values"
   Column   |            Type             |                            Modifiers
------------+-----------------------------+------------------------------------------------------------------
 id         | integer                     | not null default nextval('crypto_index_values_id_seq'::regclass)
 value      | double precision            |
 index_date | timestamp without time zone | not null
 created_at | timestamp without time zone | not null
 updated_at | timestamp without time zone | not null

Given a point in time (say "2017-07-29 11:10") stored in a variable "my_date", how would I write a Rails finder query that returns a single Rails entry that returns the row with the smallest "index_date" that was also at least 24 hours away from "my_date"? So if I had this table data

 14 | 133.951211424387 | 2017-07-31 19:10:03.235566 | 2017-07-29 19:10:03.267727 | 2017-07-31 19:10:03.267727
 15 | 133.951211424387 | 2017-07-31 19:20:03.59569  | 2017-07-28 19:20:03.629418 | 2017-07-31 19:20:03.629418
 16 | 139.104155235946 | 2017-07-31 19:30:08.037045 | 2017-07-31 19:30:08.04715  | 2017-07-31 19:30:08.04715

and given my example, I would expect the query to return the row with id "15" because the row with id "14" is not 24 hours away from my example. Normally this kind of query would work

CryptoIndexValue.where('index_date = ?', my_date - 1)

but since there isn't an entry exactly 24 hours away, it doesn't.


Solution

  • I don't think your example values quite work -- at least I don't see how you would choose that value from the table with that index date, subtracting a day. Do you mean "the row with the earliest date which is also at least 1 day in the future from my_date"?

    CryptoIndexValue.
      where('index_date > ?', my_date + 1.days).
      order(:my_date, :id).
      take
    

    I added :id to the order by in case you need a tie-break on two rows that have the same index_date, but remove it if that's impossible due to a constraint.

    Maybe you mean to subtract one day instead of adding, though.