【问题标题】:Get elements by id array and order by this array通过 id 数组获取元素并按此数组排序
【发布时间】:2017-11-16 10:00:24
【问题描述】:

例如,我希望通过 id 数组获取产品,但我希望这些产品与 id 数组的订单相同。

例如,我想要 id 为 6、3、8 的产品:

ids = [6, 3, 8]
Product.where(id: ids)

它给了我产品,但第一个是 id = 3 的产品,第二个是 id = 6...

我希望这些产品与ids 数组的顺序相同。我想要第一个 id = 6 的产品,第二个 id = 3 的产品...

如何在产品查询中做到这一点?

【问题讨论】:

    标签: ruby-on-rails activerecord ruby-on-rails-5


    【解决方案1】:

    索引应该可以工作:

    Product.where(id: ids).index_by(&:id).values_at(*ids)
    

    或者只是(在 MySQL 中检查,但如果 id 来自外部源,则在之前清理 ids):

    Product.where(id: ids).order("field(id, #{ids.join(', ')})")
    

    【讨论】:

    • 这里的问题是.order("field(id, #{ids.join(', ')})") 是一件非常糟糕的事情,因为这样activerecord 引擎不会逃避输入。例如ids = ["7); delete from products; select * from products where id in (7"]
    • @potashin,我知道 SQL 注入是什么意思,谢谢 :) 当然,你应该先清理你的输入,但无论如何我相信它比 nlogn 算法好)
    • @potashin 哪个解决方案会更快?如果是第二个,也许在之前的行中转义 SQL 查询的参数是有意义的?
    • @Ilya:我想如果你知道这些事情,你至少应该警告人们不要这样做:) 否则人们无法区分。在 MySQL 中,field() 使用的复杂性是什么?
    • @potashin,我不太清楚,但相信这个功能已经过优化(至少作为我的第一个变体)。
    【解决方案2】:

    如果您想在一个 ActiveRecord 查询中执行此操作,这取决于您使用的 RDBMS,并且将在 order 方法中包含一个原始 sql 字符串,但您也可以在纯 ruby​​ 中执行此操作:

    Product.where(id: ids).sort_by { |item| ids.index(item.id) }
    

    附:排序后集合的类将从ActiveRecord_Relation变为Array

    【讨论】:

    • 谢谢!效果很好!
    • ids 数组很大,效率极低。
    • @Ilya:一般来说,这只是一件非常低效的事情,无论在哪里,在应用程序或数据库端。
    • 那么最有效的方法是什么?
    猜你喜欢
    • 2016-05-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-21
    • 2021-10-10
    • 1970-01-01
    相关资源
    最近更新 更多