【问题标题】:Rails, ActiveRecord, query id in array of ints, keep order of passed arrayRails,ActiveRecord,在整数数组中查询 id,保持传递数组的顺序
【发布时间】:2015-05-19 17:09:40
【问题描述】:

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

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

然后我想进行查询,例如从列表中选择所有具有 id 的用户,但要保持顺序。 如果我这样做了

User.where(id: ids)

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

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

谢谢!

【问题讨论】:

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


【解决方案1】:

参考here,对于postgresql,

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

【讨论】:

    【解决方案2】:

    少用 MySQL 和 Postgresql,如果你的 id 比较小,

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

    【讨论】:

    • 这个答案效果很好 - 我的评论不是批评,只是信息以防其他人遇到同样的问题。请注意,答案中使用的sort_by 返回一个array,而不是一些宝石(如我使用的分页宝石)需要正常工作的ActiveRecord_Relation 对象。 Vic 下面的答案对我有用,因为我使用的是 postgres 并且需要有序的 AR 关系。
    • @NathanBeck 是。 sort_by 本身就是一个Array 方法
    • 正是我想要的,感谢您的回答。你摇滚!!!!
    【解决方案3】:

    如果您使用的是 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])
    

    【讨论】:

    • 请注意,如果您的列数据是字符串或文本,请先将输入的值包含在转义的双引号中。即#{ids.map{|x| "\"#{x}"\"}}.join(',')。否则,你仍然会得到 id 排序的结果。
    【解决方案4】:

    如果你使用 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
    

    【讨论】:

      【解决方案5】:
      users_by_id = User.find(ids).index_by(&:id) # Gives you a hash indexed by ID
      ids.collect {|id| users_by_id[id] }
      

      【讨论】:

        【解决方案6】:

        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的解决方案

        【讨论】:

        • 常用列名“id”在左表中出现多次
        【解决方案7】:

        如果你想得到 Model::ActiveRecord_Relation 的结果

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

        需要arel.sql来防止日志中的消息:

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2014-04-21
          • 2013-10-30
          • 2015-07-04
          • 1970-01-01
          • 2021-09-28
          • 1970-01-01
          • 2015-11-29
          相关资源
          最近更新 更多