0

I have ids array ids = [5,2,1,6].

I'd like to find all records with these ids and keep the same order as in the ids array.

Regular records = Product.find(ids) does not keep this order(not sure, but probably it sorts by id).

Marcin Doliwa
  • 3,639
  • 3
  • 37
  • 62
  • https://api.rubyonrails.org/classes/ActiveRecord/FinderMethods.html#method-i-find - `records = Product.find(ids)` should keep order in recent Rails versions. – konyak Dec 14 '20 at 23:02

3 Answers3

6

Try this:

ids = [5,2,1,6]
records = Product.find(ids).index_by(&:id).values_at(*ids)
Gagan Gami
  • 10,121
  • 1
  • 29
  • 55
0

The best way to do this is using a CASE statement (Postgres).

def order_by_id(ids)
  order_by = ["case"]
    ids.each_with_index.map do |id, index|
    order_by << "WHEN id=#{ActiveRecord::Base.connection.quote id} THEN #{index}"
  end
  order_by << "end"
  order(order_by.join(" "))
end

That should get you most of the way there.

jstoup111
  • 108
  • 6
  • Using string interpolation to build SQL queries is an invitation for SQL injection attacks. Use Rails' built-in parameter binding. – Jordan Running Jul 07 '16 at 13:06
  • @Jordan absolutely. This gets us part of the way there and isn't a complete solution. I'll update though. – jstoup111 Jul 07 '16 at 13:08
-1

This will match each id to a product

ids.map{ |id| Product.find(id) }

ProZsolt
  • 122
  • 1
  • 7
  • This will do one query per element in the ids array, which is something you don't really want. – j-dexx Jul 07 '16 at 13:09
  • Imagine you have 10000 ids, you will hit the database 10000 times, while this can be done with a single query. – wout Aug 29 '19 at 12:16