简体   繁体   中英

Order and sort_by difference in Ruby on Rails ActiveRecord

I am trying to sort my data according to timestamp field in my controller, note that the timestamp field may be null and may have some value. I wrote the following query.

@item = Item.sort_by(&:item_timestamp).reverse
            .paginate(:page => params[:page], :per_page =>5)

But this gives error when I have items that have time_timestamp field value as NULL, but following query works.

@item = Item.order(:item_timestamp).reverse
            .paginate(:page => params[:page], :per_page => 5)

Can anybody tell the difference between these two queries, and in which condition to use which one?

And I am using order and reverse to get the latest items from the database, Is this the best way or there are other best ways to get the latest data from database in terms of performance?

sort_by is executed in Ruby, so if you have a nil value, things will break in a way similar to this:

[3, nil, 1].sort
#=> ArgumentError: comparison of Fixnum with nil failed

order is executed by your RDBMS, which generally will do fine with NULL values. You can even specify where you want to put the NULL VALUES , by adding NULL FIRST (usually the default) or NULL LAST to your ORDER BY clause?

.sort_by is a Ruby method from Enumerable that is used to sort arrays (or array like objects). Using .sort_by will cause all the records to be loaded from the database into the servers memory, which can lead to serious performance problems (as well as your issue with nil values).

.order is a ActiveRecord method that adds a ORDER BY clause to the SQL select statement. The database will handle sorting the records. This is preferable in 99% of cases.

嘿,你不需要在那个查询中排序,它会工作很长时间,如果你使用数据库,你应该总是使用:order ,你的问题有解决方案

@item = Item.order('item_timestamp DESC NULLS LAST').paginate(:page => params[:page], :per_page => 5)

As it was said before me, .order is quicker, and it's enough in most cases, but sometimes you need sort_by, if you want to sort by value in a relation for example.

If you have a posts table and a view_counters table, where you have the number of views by article, you can't easily sort your posts by total views with .order.

But with sort_by, you can just do:

posts = @user.posts.joins(:view_counter)
@posts = posts.sort_by { |p| p.total_views }

.sort_by going to browse each element, get the relation value, then sort by the value of this relation, just with one code line.

You can further reduce the code with &:[attributeName] , for example:

@posts = posts.sort_by(&:total_views)

Also, for your last question about the reverse, you can do this:

Item.order(item_timestamp: :desc)

When you use sort_by you break active record caching and as pointed out before, you load all the records into RAM memory.

When writing down queries, please always think about the SQL and the memory world, they are 2 separate things. It is like having an archive (SQL) and cart (Memory) where you put the files you take out of the archive to use later.

As most people mentioned the main difference is sort_by is a Ruby method and order is Rails ActiveRecord method. However, the scenario where to use them may vary case by case. For example you may have a scenario where sort_by may be appropriate if you already retrieved the data from the DB and want to sort on the loaded data. If you use order on then you might introduce n+1 issue and go to the database again while you already have the data loaded.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM