5

I am pretty new to ROR and Postgre and i'm in trouble to achieve this.

I have a Working_hour Model and a Merchant Model, where merchant has_many working_hours and working_hour belongs to Merchant. The merchant can have two or mores working_hours for the same day.

My view:

 <% @merchant.working_hours.order(:day).group_by(&:day).each do |dia, whs| %>
   <%= t(:"date.abbr_day_names")[dia.to_i] %> : 
     <% whs.each do |wh| %>
       <li>
         <%= wh.oppening_hour.to_formatted_s(:time)  %> -
         <%= wh.close_hour.to_formatted_s(:time)  %>
       </li>
     <% end %>
  <% end %>

When I display at the view ordered by day the data retrieved are (note that the opening hour are unordered):

Mon: 
17:00-20:00
10:00-13:00
Tue:
18:00-21:00 
10:00-13:00

I want to group by day of week and ordering first by day of week and second by opening hour :

Mon: 
10:00-13:00
17:00-20:00
Tue:
10:00-13:00
18:00-21:00 

But as you can see, currently, I'm using the ruby layer to do that what brings performance issues. How can achieve this using the database layer?

pdoherty926
  • 9,895
  • 4
  • 37
  • 68
user1301037
  • 523
  • 1
  • 7
  • 19

4 Answers4

2

Quick Postgres example if you're willing to store the data in DB table (on randomly created dataset):

-- The query:
SELECT      to_char( mytime, 'day' ) as weekday,                -- example to get weekday name
            extract( dow from mytime ) as weekday_num,          -- example to get weekday number
            format(                                             -- format the way example output was given
                '%s - %s',
                date_trunc( 'hour', opening_time )::time(0),    -- get opening hour (without milliseconds)
                date_trunc( 'hour', closing_time )::time(0)     -- get closing hour (without milliseconds)
            ) as working_hours
FROM        mytable
GROUP BY    mytime,         -- to secure accurate ordering by timestamp
            weekday,        
            working_hours
ORDER BY    mytime,
            working_hours;

-- Result:
  weekday  | weekday_num |    working_hours
-----------+-------------+---------------------
 monday    |           1 | 08:00:00 - 17:00:00
 tuesday   |           2 | 08:00:00 - 16:00:00
 tuesday   |           2 | 08:00:00 - 17:00:00
 wednesday |           3 | 08:00:00 - 12:00:00
 thursday  |           4 | 08:00:00 - 12:00:00
 thursday  |           4 | 08:00:00 - 16:00:00
 friday    |           5 | 08:00:00 - 15:00:00
 friday    |           5 | 08:00:00 - 18:00:00

Postgres documentation links that might come handy:

https://www.postgresql.org/docs/current/static/functions-datetime.html https://www.postgresql.org/docs/current/static/functions-formatting.html https://www.postgresql.org/docs/current/static/functions-string.html#FUNCTIONS-STRING-FORMAT

P.S. Hopefully gives some ideas how to solve it in database.

Kristo Mägi
  • 1,584
  • 12
  • 15
  • How can I call this on rails? Using Scope? Can you give me an example how to abstract this query to rails? – user1301037 Oct 05 '16 at 22:54
  • @user1301037 – I'm not expert on Ruby, but ain't using Activerecord to execute SQL help on this like given example(s) here: http://stackoverflow.com/questions/14824453/rails-raw-sql-example ? – Kristo Mägi Oct 06 '16 at 08:20
2

The working hour should be ordered by opening_hour as you will show the opening hour in UI in ascending order. Once the working hour is ordered, the result can be grouped by day.

<% @merchant.working_hours.order(:opening_hour).group_by(&:day).each do |dia, whs| %> <%= t(:"date.abbr_day_names")[dia.to_i] %> : <% whs.each do |wh| %> <li> <%= wh.opening_hour.to_formatted_s(:time) %> - <%= wh.close_hour.to_formatted_s(:time) %> </li> <% end %> <% end %>

Minu
  • 101
  • 5
2
<% day = nil %>
<% @merchant.working_hours.order(:day, :oppening_hour).each do |wh| %>
  <% if wh.day != day %>
    <% day = wh.day %>
    <%= t(:"date.abbr_day_names")[day.to_i] %> :
  <% end %>
  <li>
    <%= wh.oppening_hour.to_formatted_s(:time)  %> -
    <%= wh.close_hour.to_formatted_s(:time)  %>
  </li>
<% end %>
Oleksandr Avoiants
  • 1,889
  • 17
  • 24
0

Why you just can't order by two fields: by "day" and by "opening_hour"?

<% @merchant.working_hours.order(:day).order(:oppening_hour).group_by(&:day).each do |dia, whs| %>
   <%= t(:"date.abbr_day_names")[dia.to_i] %> : 
     <% whs.each do |wh| %>
       <li>
         <%= wh.oppening_hour.to_formatted_s(:time)  %> -
         <%= wh.close_hour.to_formatted_s(:time)  %>
       </li>
     <% end %>
  <% end %>