动态查询构建器堆栈太深,无法进行 Arel 查询 Rails
Dynamic query builder stack too deep for Arel query Rails
我正在寻找一种在 Rails 中构建大型动态查询并将更新应用于给定 ActiveRecord 关系的方法:
例如:
my_big_set = Set.new(big_array)
to_update_relationship = my_big_set.reduce(none) do |query, values_to_check|
where('condition = ? and condition_two = ?', values_to_check[:first], values_to_check[:two]).or(query)
end
to_update_relationship.update_all(field_to_update: true)
在to_update_relationship
不太大的时候效果很好。但是,如果它变大,那么 reduce
输出会在构建 Arel 查询时触发 SystemStackError: stack level too deep
错误。
有没有聪明的方法来解决这个问题? (除了拆分输入或增加 ruby 系统堆栈大小)。
谢谢
PS: 使用 rails 6 和 ruby 2.7
您可以使用聚合函数(例如,postgresql STRING_AGG
或 mysql GROUP_CONCAT
)来收集 [condition, condition_two] 对,然后检查这些对 IN
你的要求条件。
假设您使用 postgresql,并且条件类似于 [{first: 1, two: 2}, {}, ...]
pair_conditions = conditions.map {|pair| pair.values.join(",")} # ["1,2", ...]
Solution.group(:id, :condition, :condition_two)
.having("STRING_AGG(condition::TEXT || ',' || condition_two::TEXT, '')
IN (?)", pair_conditions)
上述查询将 group
(condition, condition_two) 并将它们连接到格式为“condition,condition_two”的字符串,以便它们能够与预定义条件进行比较关于 having
条款。
我最后的解决办法是:
my_big_set = Set.new(big_array)
subquery = '(condition = ? and condition_two = ?)'
query = Array.new(my_big_set, subquery).join(' OR ')
query_values = my_big_set.map do |values_to_check|
[values_to_check[:first], values_to_check[:two]]
end.flatten
where(query, *query_values).update_all(field_to_update: true)
这样,我们构造:
- SQL 查询
- 要传递给
where()
的值
- 我们仍然使用活动记录
where()
以防止注入等...
这解决了限制!
我正在寻找一种在 Rails 中构建大型动态查询并将更新应用于给定 ActiveRecord 关系的方法:
例如:
my_big_set = Set.new(big_array)
to_update_relationship = my_big_set.reduce(none) do |query, values_to_check|
where('condition = ? and condition_two = ?', values_to_check[:first], values_to_check[:two]).or(query)
end
to_update_relationship.update_all(field_to_update: true)
在to_update_relationship
不太大的时候效果很好。但是,如果它变大,那么 reduce
输出会在构建 Arel 查询时触发 SystemStackError: stack level too deep
错误。
有没有聪明的方法来解决这个问题? (除了拆分输入或增加 ruby 系统堆栈大小)。
谢谢
PS: 使用 rails 6 和 ruby 2.7
您可以使用聚合函数(例如,postgresql STRING_AGG
或 mysql GROUP_CONCAT
)来收集 [condition, condition_two] 对,然后检查这些对 IN
你的要求条件。
假设您使用 postgresql,并且条件类似于 [{first: 1, two: 2}, {}, ...]
pair_conditions = conditions.map {|pair| pair.values.join(",")} # ["1,2", ...]
Solution.group(:id, :condition, :condition_two)
.having("STRING_AGG(condition::TEXT || ',' || condition_two::TEXT, '')
IN (?)", pair_conditions)
上述查询将 group
(condition, condition_two) 并将它们连接到格式为“condition,condition_two”的字符串,以便它们能够与预定义条件进行比较关于 having
条款。
我最后的解决办法是:
my_big_set = Set.new(big_array)
subquery = '(condition = ? and condition_two = ?)'
query = Array.new(my_big_set, subquery).join(' OR ')
query_values = my_big_set.map do |values_to_check|
[values_to_check[:first], values_to_check[:two]]
end.flatten
where(query, *query_values).update_all(field_to_update: true)
这样,我们构造:
- SQL 查询
- 要传递给
where()
的值
- 我们仍然使用活动记录
where()
以防止注入等...
这解决了限制!