Multiple order values for find_with_reputation - ruby-on-rails

The following function sorts the businesses (relation) by votes descending (using the active record reputation system link to gem).
#businesses = Business.find_with_reputation(:votes, :all, order: "votes desc")
How would I add a secondary order value so that it sorts by votes but if votes are equal it sorts by created_at (oldest at the top)?
Is it simply:
#businesses = Business.find_with_reputation(:votes, :all, order: "votes desc, created_at desc")

I suspect that your proposed answer is going to result in a SQL error because 'created_at' probably occurs in both the reputation table and the Business table. To get around that, I'd suggest being specific on created_at.
Business.find_with_reputation(:votes, :all, order: "votes desc, businesses.created_at desc")
However, I'd suggest instead that you use the id column. DBs will be faster with INTs and the sort sequence should be the same.
Business.find_with_reputation(:votes, :all, order: "votes desc, businesses.id desc")

Related

How sorting works in ruby on rails? when there are multiple fields to sort in a single query

I have a model with the fields price, min_price,max_price, discount,in my product table. if I want to execute ascending descending orders, how that will get executed when we apply for an order on multiple fields. for example like below.
#products = Product.order("price asc").order("min_price desc").order("max_price asc").order("updated_at asc") (Query might be wrong but for reference im adding)
will it order as per the order sequence ?
If you append .to_sql to that, it will show the generated SQL so you can investigate yourself.
I tried a similar query:
Book.select(:id).order("id asc").order("pub_date desc").to_sql
=> "SELECT \"books\".\"id\" FROM \"books\" ORDER BY id asc, pub_date desc"
You might instead:
Book.select(:id).order(id: :asc, pub_date: :desc).to_sql
=> "SELECT \"books\".\"id\" FROM \"books\" ORDER BY \"books\".\"id\" ASC, \"books\".\"pub_date\" DESC"
... which you see adds the table name in, so is more reliable when if you are accessing multiple tables

Sorting record array twice while maintaining initial sort

so I have the following query for my companies
companies.where(industry: industries_queried)
I would like to sort them, so that the first records returned are the ones with plan_id == 3, then 2, then 1. (descendingly)
But then, I would also like to arrange each of these 4 parts, so that they are sorted alphabetically per name.
How would I go about doing this in Rails 5?
The Active Record Query Interface guide, gives us the following info on ordering records.
4 Ordering
To retrieve records from the database in a specific order, you can use
the order method.
For example, if you're getting a set of records and want to order them
in ascending order by the created_at field in your table:
Customer.order(:created_at)
# OR
Customer.order("created_at")
You could specify ASC or DESC as well:
Customer.order(created_at: :desc)
# OR
Customer.order(created_at: :asc)
# OR
Customer.order("created_at DESC")
# OR
Customer.order("created_at ASC")
Or ordering by multiple fields:
Customer.order(orders_count: :asc, created_at: :desc)
# OR
Customer.order(:orders_count, created_at: :desc)
# OR
Customer.order("orders_count ASC, created_at DESC")
# OR
Customer.order("orders_count ASC", "created_at DESC")
Applying this to your issue you would end up with:
companies.where(industry: industries_queried).order(plan_id: :desc, name: :asc)

How use order by condition

Is it possible to sort the data on a condition?
For example, figuratively, .order( "expiration_date <?", Time.current, :desc )
The ORDER BY keyword is used to sort the result-set by one or more columns.
The ORDER BY keyword sorts the records in ascending order by default. To sort the records in a descending order, you can use the DESC keyword.
you can sort by using something like :-
sorted = #records.sort_by &:created_at
or try where by first getting the resultset and then sorting it:-
#records.where( "expiration_date <?", Time.current).order( :created_at, :desc )
Moreover you can paginate easily;-
#records.paginate(:page => params[:page], :per_page => 15)#.order(" created_at ASC")

Order by two things in two different styles

Theoretically what I want is this:
:order => "column1 ASC, column2 DESC"
But column1 is actually not a column in my case but an aggregated value:
:order => relations.count
How can I order by two columns when one of those is actually an aggregated value?
Btw: Counter-Cache is not an option (because it is outdated when I need it)
:order => "COUNT(*), column2 DESC"
To order/group/etc by a calculated value, you have to specify it in the corresponding clause, in your case using a (possibly left) join too:
Something.select("somethings.*, COUNT(others.id)").
joins("LEFT JOIN others ON others.something_id = somethings.id").
group("somethings.*").
order("COUNT(others.id), column2 DESC")

Ruby on Rails: how do I sort with two columns using ActiveRecord?

I want to sort by two columns, one is a DateTime (updated_at), and the other is a Decimal (Price)
I would like to be able to sort first by updated_at, then, if multiple items occur on the same day, sort by Price.
In Rails 4 you can do something similar to:
Model.order(foo: :asc, bar: :desc)
foo and bar are columns in the db.
Assuming you're using MySQL,
Model.all(:order => 'DATE(updated_at), price')
Note the distinction from the other answers. The updated_at column will be a full timestamp, so if you want to sort based on the day it was updated, you need to use a function to get just the date part from the timestamp. In MySQL, that is DATE().
Thing.find(:all, :order => "updated_at desc, price asc")
will do the trick.
Update:
Thing.all.order("updated_at DESC, price ASC")
is the Rails 3 way to go. (Thanks #cpursley)
Active Record Query Interface lets you specify as many attributes as you want to order your query:
models = Model.order(:date, :hour, price: :desc)
or if you want to get more specific (thanks #zw963 ):
models = Model.order(price: :desc, date: :desc, price: :asc)
Bonus: After the first query, you can chain other queries:
models = models.where('date >= :date', date: Time.current.to_date)
Actually there are many ways to do it using Active Record. One that has not been mentioned above would be (in various formats, all valid):
Model.order(foo: :asc).order(:bar => :desc).order(:etc)
Maybe it's more verbose, but personally I find it easier to manage.
SQL gets produced in one step only:
SELECT "models".* FROM "models" ORDER BY "models"."etc" ASC, "models"."bar" DESC, "models"."foo" ASC
Thusly, for the original question:
Model.order(:updated_at).order(:price)
You need not declare data type, ActiveRecord does this smoothly, and so does your DB Engine
Model.all(:order => 'updated_at, price')
None of these worked for me!
After exactly 2 days of looking top and bottom over the internet, I found a solution!!
lets say you have many columns in the products table including: special_price and msrp. These are the two columns we are trying to sort with.
Okay, First in your Model
add this line:
named_scope :sorted_by_special_price_asc_msrp_asc, { :order => 'special_price asc,msrp asc' }
Second, in the Product Controller, add where you need to perform the search:
#search = Product.sorted_by_special_price_asc_msrp_asc.search(search_params)

Resources