Rails,ActiveRecord,在int数组中查询id,保持传递数组的顺序

时间:2015-03-17 10:06:49

标签: ruby-on-rails ruby-on-rails-4

我正在考虑问题的最佳解决方案。 假设我们有一个ActiveRecord模型的ID列表:

ids = [1, 100, 5, 30, 4, 2, 88, 44]

然后我想进行查询,从列表中选择所有用户,例如使用ID,但保留订单。 如果我做

User.where(id: ids)

响应将是按ID排序的用户列表,但我希望订单与数组中的顺序相同。

您认为这是最好的解决方案吗?选择所有用户,然后操作ActiveRecord对象列表?也许有一种更聪明的方法可以做到这一点。

谢谢!

7 个答案:

答案 0 :(得分:10)

参考here,对于postgresql,

User.where(id: ids).order("position(id::text in '#{ids.join(',')}')")

答案 1 :(得分:8)

如果您使用的是MySQL,则可以使用FIELD订购结果:

class User < ActiveRecord::Base
  def self.find_in_order(ids)
    self.where(id: ids).order("FIELD(id, #{ids.join(',')})")
  end
end

User.find_in_order([1, 100, 5, 30, 4, 2, 88, 44])

答案 2 :(得分:6)

少用MySQL和Postgresql,如果你的ID很小,

User.where(id: ids).sort_by { |u| ids.index(u.id) }

答案 3 :(得分:1)

如果您使用的是Postgres,可以使用intarray

class User < ActiveRecord::Base
  def self.find_in_order(ids)
    self.where(id: ids).order("idx(array[#{ids.join(',')}], id)")
  end
end

你应该首先启动模块

CREATE EXTENSION intarray

答案 4 :(得分:0)

users_by_id = User.find(ids).index_by(&:id) # Gives you a hash indexed by ID
ids.collect {|id| users_by_id[id] }

答案 5 :(得分:0)

Postgres(9.4或更高版本)的另一种可能性:

ordered_ids = [1, 100, 5, 30, 4, 2, 88, 44]
User.joins("join unnest('{#{ordered_ids.join(',')}}'::int[]) WITH " \
           "ORDINALITY t(id, ord) USING (id)").reorder('t.ord')

请注意,重新排序非常重要。

基于https://stackoverflow.com/a/35456954

的解决方案

答案 6 :(得分:-1)

如果要获取Model :: ActiveRecord_Relation的结果

order(Arel.sql("field(id, ids.join(', ') asc"))

需要Arel.sql来防止消息记录在日志中:

  

危险的查询方法(其参数用作原始SQL的方法)   用非属性参数调用