Leo*_*sov 93 ruby activerecord ruby-on-rails
当你Something.find(array_of_ids)在Rails中,所得到的数组的顺序不依赖的顺序array_of_ids.
有没有办法找到并保存订单?
ATM我根据ID的顺序手动对记录进行排序,但这有点蹩脚.
UPD:如果可以使用:orderparam和某种SQL子句指定顺序,那么如何?
Gun*_*ars 78
奇怪的是,没有人提出这样的建议:
index = Something.find(array_of_ids).group_by(&:id)
array_of_ids.map { |i| index[i].first }
Run Code Online (Sandbox Code Playgroud)
除了让SQL后端执行它之外,它的效率也很高.
编辑:为了改进我自己的答案,你也可以这样做:
Something.find(array_of_ids).index_by(&:id).slice(*array_of_ids).values
Run Code Online (Sandbox Code Playgroud)
#index_by并且#slice是ActiveSupport中分别用于数组和散列的非常方便的补充.
小智 69
答案仅适用于mysql
mysql中有一个名为FIELD()的函数
以下是如何在.find()中使用它:
>> ids = [100, 1, 6]
=> [100, 1, 6]
>> WordDocument.find(ids).collect(&:id)
=> [1, 6, 100]
>> WordDocument.find(ids, :order => "field(id, #{ids.join(',')})")
=> [100, 1, 6]
For new Version
>> WordDocument.where(id: ids).order("field(id, #{ids.join ','})")
Run Code Online (Sandbox Code Playgroud)
Aje*_*i32 38
正如迈克伍德豪斯在他的回答中所说的,这种情况发生时,Rails正在使用带有a的SQL查询WHERE id IN... clause来检索一个查询中的所有记录.这比单独检索每个id要快,但正如您所注意到的那样,它不会保留您要检索的记录的顺序.
为了解决这个问题,您可以根据查找记录时使用的原始ID列表在应用程序级别对记录进行排序.
基于根据另一个数组的元素对数组进行排序的许多优秀答案,我推荐以下解决方案:
Something.find(array_of_ids).sort_by{|thing| array_of_ids.index thing.id}
Run Code Online (Sandbox Code Playgroud)
或者如果你需要更快一些东西(但可以说可读性稍差),你可以这样做:
Something.find(array_of_ids).index_by(&:id).values_at(*array_of_ids)
Run Code Online (Sandbox Code Playgroud)
gin*_*ime 20
这似乎适用于postgresql(源代码) - 并返回一个ActiveRecord关系
class Something < ActiveRecrd::Base
scope :for_ids_with_order, ->(ids) {
order = sanitize_sql_array(
["position((',' || id::text || ',') in ?)", ids.join(',') + ',']
)
where(:id => ids).order(order)
}
end
# usage:
Something.for_ids_with_order([1, 3, 2])
Run Code Online (Sandbox Code Playgroud)
也可以扩展到其他列,例如对于name列,使用position(name::text in ?)...
Jac*_*lyn 18
正如我在这里回答的那样,我刚刚发布了一个gem(order_as_specified),允许你像这样进行本机SQL排序:
Something.find(array_of_ids).order_as_specified(id: array_of_ids)
Run Code Online (Sandbox Code Playgroud)
就我能够测试而言,它在所有RDBMS中本地工作,并返回可以链接的ActiveRecord关系.
根据官方文档,应该是相同的顺序。
https://api.rubyonrails.org/classes/ActiveRecord/FinderMethods.html#method-i-find
Something.find(array_of_ids)
结果数组的顺序应与 array_of_ids 的顺序相同。我已经在 Rails 6 中对此进行了测试。
不可能在SQL中不可能在所有情况下工作,你可能需要为ruby中的每个记录或订单编写单个查找,尽管有可能使用专有技术使其工作:
第一个例子:
sorted = arr.inject([]){|res, val| res << Model.find(val)}
Run Code Online (Sandbox Code Playgroud)
非常缺乏
第二个例子:
unsorted = Model.find(arr)
sorted = arr.inject([]){|res, val| res << unsorted.detect {|u| u.id == val}}
Run Code Online (Sandbox Code Playgroud)
有一个 gem find_with_order可以让您通过使用本机 SQL 查询来高效地完成此操作。
它同时支持Mysql和PostgreSQL。
例如:
Something.find_with_order(array_of_ids)
Run Code Online (Sandbox Code Playgroud)
如果你想要关系:
Something.where_with_order(:id, array_of_ids)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
44677 次 |
| 最近记录: |