Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Clean way to find ActiveRecord objects by id in the order specified

I want to obtain an array of ActiveRecord objects given an array of ids.

I assumed that

Object.find([5,2,3]) 

Would return an array with object 5, object 2, then object 3 in that order, but instead I get an array ordered as object 2, object 3 and then object 5.

The ActiveRecord Base find method API mentions that you shouldn't expect it in the order provided (other documentation doesn't give this warning).

One potential solution was given in Find by array of ids in the same order?, but the order option doesn't seem to be valid for SQLite.

I can write some ruby code to sort the objects myself (either somewhat simple and poorly scaling or better scaling and more complex), but is there A Better Way?

like image 326
Andrew Grimm Avatar asked Apr 29 '09 10:04

Andrew Grimm


People also ask

What is an ActiveRecord object?

In Active Record, objects carry both persistent data and behavior which operates on that data. Active Record takes the opinion that ensuring data access logic as part of the object will educate users of that object on how to write to and read from the database.

Is ActiveRecord an ORM?

ActiveRecord is an ORM. It's a layer of Ruby code that runs between your database and your logic code. When you need to make changes to the database, you'll write Ruby code, and then run "migrations" which makes the actual changes to the database.

What does ActiveRecord base mean?

ActiveRecord::Base indicates that the ActiveRecord class or module has a static inner class called Base that you're extending.


1 Answers

It's not that MySQL and other DBs sort things on their own, it's that they don't sort them. When you call Model.find([5, 2, 3]), the SQL generated is something like:

SELECT * FROM models WHERE models.id IN (5, 2, 3) 

This doesn't specify an order, just the set of records you want returned. It turns out that generally MySQL will return the database rows in 'id' order, but there's no guarantee of this.

The only way to get the database to return records in a guaranteed order is to add an order clause. If your records will always be returned in a particular order, then you can add a sort column to the db and do Model.find([5, 2, 3], :order => 'sort_column'). If this isn't the case, you'll have to do the sorting in code:

ids = [5, 2, 3] records = Model.find(ids) sorted_records = ids.collect {|id| records.detect {|x| x.id == id}}  
like image 114
tomafro Avatar answered Sep 20 '22 21:09

tomafro