合并两个 ActiveRecord::Relation 对象

问题描述 投票:0回答:10

假设我有以下两个对象:

first_name_relation = User.where(:first_name => 'Tobias') # ActiveRecord::Relation
last_name_relation  = User.where(:last_name  => 'Fünke') # ActiveRecord::Relation

是否可以将这两种关系结合起来生成一个包含这两个条件的

ActiveRecord::Relation
对象?

注意:我知道我可以链接 wheres 来获得此行为,我真正感兴趣的是我有两个单独的

ActiveRecord::Relation
对象的情况。

ruby-on-rails rails-activerecord arel
10个回答
258
投票

如果您想使用

AND
(交叉点)进行组合,请使用
merge
:

first_name_relation.merge(last_name_relation)

如果您想使用

OR
(联合)进行组合,请使用
or
:

first_name_relation.or(last_name_relation)

仅适用于 ActiveRecord 5+;对于 4.2,安装 where-or 向后移植。


42
投票

关系对象可以转换为数组。这使得之后无法对它们使用任何 ActiveRecord 方法,但我不需要这样做。我这样做了:

name_relation = first_name_relation + last_name_relation

Ruby 1.9,Rails 3.2


24
投票

merge
实际上不像
OR
那样工作。简直就是交集(
AND
)

我努力解决这个问题,将 ActiveRecord::Relation 对象合并为一个,但没有找到任何可行的解决方案。

我没有寻找从这两个集合创建并集的正确方法,而是专注于集合的代数。您可以使用德摩根定律

以不同的方式做到这一点

ActiveRecord 提供了 merge 方法(AND),也可以使用 not 方法或 none_of(NOT)。

search.where.none_of(search.where.not(id: ids_to_exclude).merge(search.where.not("title ILIKE ?", "%#{query}%")))

你这里有 (A u B)' = A' ^ B'

更新: 上述解决方案适用于更复杂的情况。 在你的情况下,这样就足够了:

User.where('first_name LIKE ? OR last_name LIKE ?', 'Tobias', 'Fünke')

16
投票

即使在许多奇怪的情况下,我也能够通过使用 Rails 的内置 Arel 来完成此任务。

User.where(
  User.arel_table[:first_name].eq('Tobias').or(
    User.arel_table[:last_name].eq('Fünke')
  )
)

这通过使用 Arel 的 or 合并了两个 ActiveRecord 关系。


合并,正如这里所建议的那样,对我来说不起作用。它从结果中删除了第二组关系对象。


15
投票

有一个叫做 active_record_union 的宝石 这可能就是您正在寻找的。

其示例用法如下:

current_user.posts.union(Post.published)
current_user.posts.union(Post.published).where(id: [6, 7])
current_user.posts.union("published_at < ?", Time.now)
user_1.posts.union(user_2.posts).union(Post.published)
user_1.posts.union_all(user_2.posts)

14
投票

这就是我“处理”它的方式,如果您使用 pluck 获取每个记录的标识符,将数组连接在一起,然后最后对这些连接的 id 进行查询:

  transaction_ids = @club.type_a_trans.pluck(:id) + @club.type_b_transactions.pluck(:id) + @club.type_c_transactions.pluck(:id)
  @transactions = Transaction.where(id: transaction_ids).limit(100)

6
投票

如果你有一个 ActiveRecord 关系数组并想将它们全部合并,你可以这样做

array.inject(:merge) # like where AND

array.inject(:or) # like where OR

1
投票

在使用 or 不可压缩的情况下,我使用类似的方法来获取 ActiveRecord_Relation 对象

User.from("(#{complex_raw_query} UNION #{complex_raw_query}) AS users")

0
投票

暴力破解:

first_name_relation = User.where(:first_name => 'Tobias') # ActiveRecord::Relation
last_name_relation  = User.where(:last_name  => 'Fünke') # ActiveRecord::Relation

all_name_relations = User.none
first_name_relation.each do |ar|
  all_name_relations.new(ar)
end
last_name_relation.each do |ar|
  all_name_relations.new(ar)
end

0
投票

希望这对那里的人有用——您可以进行第二次查询以按 id 查找匹配项:

ids = last_name_relation.ids + first_name_relation.ids
User.where(id: ids)

我意识到这对于 3 个数据库请求可能不是最有效的,但它可以完成工作并且很容易理解。

© www.soinside.com 2019 - 2024. All rights reserved.