组合两个 ActiveRecord::Relation 对象

假设我有以下两个对象:

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

是否有可能将这两个关系结合起来产生一个包含这两个条件的ActiveRecord::Relation对象?

注意:我知道我可以链接where来获得这个行为,我真正感兴趣的是我有两个单独的ActiveRecord::Relation对象的情况。

134186 次浏览

如果你想使用AND (intersection)进行组合,请使用merge:

first_name_relation.merge(last_name_relation)

如果你想使用OR (union)进行组合,请使用or__:

first_name_relation.or(last_name_relation)

__只在ActiveRecord 5+;为4.2安装在哪儿举行或后端端口。

关系对象可以转换为数组。这否定能够使用任何ActiveRecord方法在他们之后,但我不需要。我是这样做的:

name_relation = first_name_relation + last_name_relation

Ruby 1.9, rails 3.2

merge实际上不像OR那样工作。它是简单的交集(AND)

我努力解决这个问题,将ActiveRecord::Relation对象组合成一个,我没有找到任何适合我的工作解决方案。

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

ActiveRecord提供合并方法(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'

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

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

我已经能够做到这一点,即使在许多奇怪的情况下,通过使用Rails内置的Arel

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

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


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

有一个名为active_record_union的宝石 这可能就是你要找的。< / p >

它的示例用法如下:

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)

如果您有一个activerecord关系数组,并希望合并它们,您可以这样做

array.inject(:merge)

蛮力吧:

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

这是我“处理”它的方式,如果你使用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)

希望这对某些人有用——你可以进行第二个查询,通过id找到匹配:

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

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

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

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