I have some code like this:
stages.each do |stage|
start_activity = stage.activities.where('created_at < ?', @start_time).first
end_activity = stage.activities.where('created_at < ?', @end_time).first
# ...
end
Which fills my logs with a few screens worth of queries like these:
Activity Load (0.3ms) SELECT "activities".* FROM "activities"
WHERE "activities"."stage_id" = $1
AND (created_at < '2017-01-31 08:00:00.000000')
ORDER BY id DESC, "activities"."created_at" DESC
LIMIT 1
[["stage_id", 11548]]
Activity Load (0.3ms) SELECT "activities".* FROM "activities"
...
(Activity has a default scoped order of id DESC
)
So I'm hoping there is a way to fetch all the activities I need per timestamp in a single query. This would reduce my number of from activity_count * 2
to simply 2
.
Here's what I tried, but I don't think distinct
is properly being used here.
Activity
.select('DISTINCT ON (stage_id) *')
.where(stage: stages)
.where('created_at < ?', @start_time)
.reorder('id DESC')
Which spews out:
ActiveRecord::StatementInvalid (PG::InvalidColumnReference: ERROR: SELECT DISTINCT ON expressions must match initial ORDER BY expressions
LINE 1: SELECT DISTINCT ON (stage_id) * FROM "activities" WHERE "act...
^
: SELECT DISTINCT ON (stage_id) * FROM "activities" WHERE "activities"."stage_id" IN (11548, 11549, <more ids snipped>, 12432, 12433) AND (created_at < '2017-01-31 08:00:00.000000') ORDER BY id DESC):
What I mean to do here is to say: give me all activities that have a stage_id
in an array of stages
, where the created_at
date is nearest to (without going over) a timestamp. What I want to get back is a single activity record for every stage in stages
.
Is it possible to do this in 1
query rather than stages.count
queries?