【问题标题】:Rails find records using an array of hashesRails 使用哈希数组查找记录
【发布时间】:2017-11-18 02:29:08
【问题描述】:

(使用in 子句按字段对选择查询)

我有一个如下所示的哈希数组:

[ {product_id: 7629, group_id: 4}, {product_id: 8202, group_id: 3} ]

我要返回的是Items 表中与数组中的一对字段匹配的所有记录。

在 SQL 中会这样检索:

SELECT * 
FROM items
WHERE (product_id, group_id) IN (VALUES (7629,4), (8202,3))

但是我在使用 rails .where 子句时遇到了麻烦。这甚至可能吗?

【问题讨论】:

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


    【解决方案1】:

    在这种情况下,我认为使用 SQL 的 IN 没有任何好处。

    我会使用where 作为第一个条件,并使用or 链接所有其他条件(让 Rails 负责清理和繁重的工作):

    array = [{ product_id: 7629, group_id: 4 }, { product_id: 8202, group_id: 3 }]
    array[1..-1].inject(Model.where(array[0])) { |m, h| m.or(Model.where(h)) }
    

    【讨论】:

    • 不错!这比我建议的要好得多。但是,它正在用array.shift 修改array,我认为这并不理想。 array.drop(1).inject(Model.where(array.first)) { |m, h| m.or(Model.where(h)) } 会做同样的事情而不改变数组。
    • 更新了我的答案来解决这个问题。
    【解决方案2】:

    如果不使用 SQL,我想不出任何方法来做到这一点,即使是使用 Arel。

    由于数组不能被引用,我们必须做一些愚蠢的事情来让它仍然被净化。这不是一个很棒的 解决方案,但它是一个有效的解决方案。

    your_hashes = [ {product_id: 7629, group_id: 4}, {product_id: 8202, group_id: 3} ]
    
    # turn hashes into simple value array
    conditions = your_hashes.map { |h| [ h[:product_id], h[:group_id] ] }
    => [[7629, 4], [8202, 3]]
    
    # create a list of "(?)" values that will allow the conditions to be passed in
    values = ("(?)," * conditions.length)[0..-2]
    => "(?),(?)"
    
    # use it to look up the values
    Model.where("(product_id, group_id) IN (VALUES #{values})", *conditions)
    
    # this is the generated sql:
    SELECT "models".* FROM "models" WHERE ((product_id, group_id) IN (VALUES (7629,4),(8202,3)))
    

    【讨论】:

    • 考虑使用values = (['(?)'] * conditions.length).join(',') 来避免最后真正古怪的[0..-2] 逗号剥离。最好不要放入要立即清除的垃圾。
    • @tadman 这通常是一个好点,但这是故意的。这种替代数组语法比我使用的字符串切片慢 3.71 倍。它不是那么漂亮,但它的性能要好得多。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-10-23
    • 1970-01-01
    • 1970-01-01
    • 2016-08-18
    • 1970-01-01
    • 2018-06-14
    • 1970-01-01
    相关资源
    最近更新 更多