PostgreSQL in Rails: sorting object by two date attributes in descending order - ruby-on-rails

I have an index of active job positions. Currently, they're sorted by the most recent i.e. created_at. However, recently i've added in a renewal feature that updates a renewal_date attribute without updating the created_at.
What I want to achieve is to sort the list in descending order using both renewal_date and created_at.
jobs = Job.where(active: true).reorder("renewal_date DESC NULLS LAST", "created_at DESC")
With this code, the renewed job will always be at the top regardless of how many new jobs are created. How do I sort it so it checks for the date for both attributes and sorts it according to most recent?

Your code will order first by renewal_date with nulls at the end, and then will look at the created_at if two records have the same renewal_date.
I assume that what you want to do is something like "max(renewal_date, created_at)", which will take the "last modification date", or another custom way to compare the two fields.
If then, you can find your answer here : merge and order two columns in the same model
Job.where(active: true).reorder('GREATEST(renewal_date, created_at) DESC')

Let try a standard SQL, so it can work with all types of database:
Job.where(active: true).order('CASE WHEN renewal_date IS NULL THEN created_at ELSE renewal_date END DESC')

Related

rails order by created_at attribute of nested jsonb data

I have a bunch of customers that need to be sorted by the time they were "completed" according to our system. I can do it like this and it works ok:
customers = Customer.where(state: 'review').joins(:audits)
customers.sort_by { |c| c.onboarding_finished_at.to_i }
or...it did until it got onto our staging environment where we have enough customers with enough audits that it caused some major performance issues. Now i'm searching for a way to sort customers by the created_at attribute of the last state transition, but my query-foo is woefully inadequate.
this is a simplified version of the audits data associated with a customer. Note the audited_changes column which is jsonb:
irb(main):032:0> customers.last.audits.last
=> #<Audited::Audit id: 642691, auditable_id: 45517, action: "update", audited_changes: {"state"=>[0, 1]}, created_at: "2020-08-13 08:59:00">
I can access the audits but i can't for the life of me figure out how to get the last transition to state "1" (cause there could be multiple) and then pluck the created_at of that and then sort customers by that created_at value.
Any push in the right direction is very much appreciated!
You can do an inner joins on the table and run a query to check second element of state array (assuming that's the structure for all the records) is 1.
Customer.includes(:audits).where("audited_changes->'$.state[1]' = 1").reorder("audits.created_at asc")
Let me know if that's what you're looking for

RoR PostgresQL - Get latest, distinct values from database

I am trying to query my PostgreSQL database to get the latest (by created_at) and distinct (by user_id) Activity objects, where each user has multiple activities in the database. The activity object is structured as such:
Activity(id, user_id, created_at, ...)
I first tried to get the below query to work:
Activity.order('created_at DESC').select('DISTINCT ON (activities.user_id) activities.*')
however, kept getting the below error:
ActiveRecord::StatementInvalid: PG::InvalidColumnReference: ERROR: SELECT DISTINCT ON expressions must match initial ORDER BY expressions
According to this post: PG::Error: SELECT DISTINCT, ORDER BY expressions must appear in select list, it looks like The ORDER BY clause can only be applied after the DISTINCT has been applied. This does not help me, as I want to get the distinct activities by user_id, but also want the activities to be the most recently created activities. Thus, I need the activities to be sorted before getting the distinct activities.
I have come up with a solution that works, but first grouping the activities by user id, and then ordering the activities within the groups by created_at. However, this takes two queries to do.
I was wondering if what I want is possible in just one query?
This should work, try the following
Solution 1
Activity.select('DISTINCT ON (activities.user_id) activities.*').order('created_at DESC')
Solution 2
If not work Solution 1 then this is helpful if you create a scope for this
activity model
scope :latest, -> {
select("distinct on(user_id) activities.user_id,
activities.*").
order("user_id, created_at desc")
}
Now you can call this anywhere like below
Activity.latest
Hope it helps

.distinct not returning unique entries

I have a table of Projects, in that table, there may be the same project multiple times with the same name, however the created_at month will be different. I'm trying to select the most recent record of each project in my table. Using select works, however I need the entire record so that then I can loop through the records and print out different attributes eg price or what not.
I've tried:
Project.distinct(:project_name) – Prints all records (to check this I copied the project name and did a find and all projects with the identical name would still print out)
Project.order(project_name: :asc, created_at: :desc).uniq(:project_name) – Same result as above
Project.select(:project_name).distinct – Pulls only 1 of each, however it only selects the project name and no other data from the record.
This is the case where DISTINCT ON comes to rescue.
This should work:
Project.select("DISTINCT ON (project_name) *").order("project_name, created_at DESC")
for selecting only particular columns specify them instead of *.
Project.select("DISTINCT ON (project_name) project_name, created_at, price").order("project_name, created_at DESC")

How to sort by an associated column in this active record query

I need a few queries sorted by an associated model. I have a list of Customers that I get and I need to make sure the customer list is sorted by the last Message they received. Here are the current queries:
#open_customers = #company.customers.open.includes(:last_received_message)
#your_customers = current_user.customers.includes(:last_message)
#sidebar_customers = current_company.customers.open_or_claimed.
where("user_id = ? OR user_id IS NULL", current_user.id).
order(aasm_state: :asc).includes([:last_received_message, :user])
these are three separate queries.
#open_customers needs to be sorted by the created_at of last_received_message
#your_customers needs to be sorted by the created_at of last_message
#sidebar_customers needs to be sorted by the created_at of last_received_message
thanks!
You might try checking out Section 14: scopes here: http://guides.rubyonrails.org/active_record_querying.html
Also this website has a course called Rails 4 Outlaws that does a great job teaching scopes: https://www.codeschool.com

Rails Activerecord last 5 records based on field value

I want to fetch the last 5 records where transfer = something. Currently I'm using: Model.limit(5).order('id desc') but that shows the last 5 of Call.all. How can I express this by adding a where clause or specifying a particular value as part of the query?
Simply
Model.where(:transfer => 'something').order('id desc').limit(5)
But it might make more sense to order by created_at or updated_at instead of id.

Resources