I have the an Order model in the following
If today is 5/3
and I want to sum the previous 3 months data of order, how to do it ?
I mean I want to show the 2/1 ~ 4/30 excluding the orders in May.
If today is 2014/4/20, and I want to show the sum of previous 3 weeks data. 2014/2/1~2/15
How to do it in Rubic way ?
You want something along the lines:
date = DateTime.now.utc
Order.where('created_at >= ? and created_at <= ?', date.beginning_of_month, date.utc.end_of_month).sum('price')
Where price is the column you want to sum.
You can reuse the logic of #Santosh in order to get the dates you want =)
start_date = 3.months.ago.beginning_of_month
end_date = 1.month.ago.end_of_month
You can write your query based on these dates. Same logic can be applied for weeks also.
Related
I'm trying to iterate over each week in the calendar year and run a query.
range = Date.new(2020,3,16)..Date.new(2020,3,22)
u = User.where(created_at: range).count
But I'd like to do this for EACH week in another range (say since the beginning of this year).
Ruby's Date has a cweek function that gives you the week number but there doesn't seem to be a way to easily get from the week number to the date range.
Anyway, not sure how helpful cweek will be as I need week to run Sunday -> Saturday.
Thoughts?
I'm assuming this is Postgres and the model name is User based on your previous question.
If this blog is to to believed you can shift a date one day to get sun-sat day week.
User.group("(date_trunc('week', created_at::date + 1)::date - 1)")
.count
If you want the to select the actual week number while you are at it you can select raw data from the database instead of using ActiveRecord::Calculations#count which is pretty limited.
class User
# #return [ActiveRecord::Result]
# the raw query results with the columns count, year, week
def self.count_by_biblical_week
connection.select_all(
select(
"count(*) as count",
"date_part('year', created_at)::integer as year",
"(date_part('week', created_at::date + 1) - 1)::integer as week"
).group(:week, :year)
)
end
end
Usage:
results = User.where(created_at: Date.new(2020,3,16)..Date.new(2020,3,22))
.count_by_biblical_week
results.each do |row|
puts [row[:year], row[:week], row[:count]].join(' | ')
end
Adding the year to the group avoids ambiguity if the results span multiple years.
I am working on an hourly hotel booking application. There is a peak_seasons table which stores start_date and end_date. Peak_Seasons are pre-defined dates for current year in my application. Whenever a customer makes a booking for the selected hours then I have to check if any of those hours belongs to peak season, so that I can apply a different rate for those hours.
This operation is so frequent that I want to optimise it. Need ideas. My current pseudo code is this:
def calculate_price(customer_start_time, customer_end_time)
price = 0
(customer_start_time.to_i...customer_end_time.to_i).step(1.hour) do |hour|
//now check if this hour belongs to peak season over here
if peak_seasons?(hour)
price += price + peak_season_price
else
price += price + standard_price
end
return price
end
//peak_seasons? somewhere
def peak_seasons?(hour)
PeakSeason.where("start_date <= ? and end_date >= ?", hour.to_date, hour.to_date).any?
end
I guess this is not efficient code when hundreads of customers are checking the price for selected hours, then it will fetch data from DB for every hour selected. How to optimize it?
You could create a super efficient solution by caching all PeakSeason data and using an Interval tree (see also this answer) for calculation. But you say "I guess this is not efficient" - honestly, I advice against this kind of optimization unless you really know there is a performance problem.
You could try to select all PeakSeason records for a given interval at once.
def all_peak_seasons(customer_start_time, customer_end_time)
PeakSeason.where(":start_time BETWEEN start_date AND end_date OR "\
":end_time BETWEEN start_date AND end_date OR "\
"start_date BETWEEN :start_time AND :end_time",
{start_time: customer_start_time, end_time: customer_end_time})
end
I have a system about cars and parking tickets. I had a requirement to implement where I had to get all the tickets from the last 12 months, so I opened this question.
The requirement has changed and now I need to get the tickets from the last 12 months starting on the last ticket's date.
I know how to do that using SQL (postgres), it would be something like this example:
select *
from parking_tickets
where car_id = 25
AND
date > (select date from parking_tickets where car_id = 25 order by date desc limit 1) - INTERVAL '12 months'
order by date desc
But I would rather have it in ActiveRecord. Is there any way?
I could insert the subquery itself inside the where clause, but it would not be as nice as I would like to.
Is there a nice way to make this, something like this?
#cars = Car.includes(:parkingTickets)
.where('parkingTickets.date >= ?', MAX(parkingTickets.date) - 12.months)
.order('ID, parkingTickets.date desc')
I would like to have it done in a list of cars, so making the query before and then inserting this value in the query would not be an elegant solution, since I would have an array.
This solution should work:
Car.includes(:parking_tickets).where(id: 25, parking_tickets: {date: (ParkingTicket.where(car_id: 25).order(date: :desc).first.date - 12.month)..ParkingTicket.where(car_id: 25).order(date: :desc).first.date}).first.parking_tickets.order(date: :asc).all
I'm trying to create an array that has the total of all sales a company does for each day of the week. Right now I have something similar to this
#sales = Sale.all
#sales_total = #sales.map{|sale|sale.total.to_i}
Which returns an array of each total for every single sale.
Before turning it into an array, how can I group Sale by day, and adding total together?
I'm a fan of groupdate gem.
You ca do something like:
#sales_total = Sale.group_by_day(:created_at).order("day asc").sum(:total)
Assuming total is the column you want to sum up.
EDIT - To add a interval of time condition you can use where, for example:
#sales_total = Sale.where('created_at between ? and ?', Date.today, 1.week.ago).group_by_day(:created_at).order("day asc").sum(:total)
I need to grab the records for same day of the week for the preceeding X days of the week. There must be a better way to do it than this:
Transaction.find_by_sql "select * from transactions where EXTRACT(DOW from date) = 1 and organisation_id = 4 order by date desc limit 7"
It gets me what I need but is Postgres specific and not very "Rails-y". Date is a timestamp.
Anyone got suggestions?
How many days do you want to go back?
I have written a gem called by_star that has a dynamic finder suited for finding up to a certain number of days in the past. If the number of days was always a number you could use this finder:
Transaction.as_of_3_days_ago
If it was dynamic then I would recommend using something such as future or between, depending on if you have transactions in the future (i.e. time travel):
Transaction.future(params[:start_date].to_time)
Transaction.between(params[:start_date].to_time, Time.now)
AFAIK Rails has no any methods to do this by other way. So best, and faster, solution - build DOW index on date column and use your query.