如何合并两个ActiveRecord::Relation并返回Relation对象而非Array
问题根源
+运算符会立即执行两个Relation的查询,将结果加载为内存数组,不再保留ActiveRecord::Relation类型or方法要求两个Relation的结构完全一致(包括select字段、关联join、分组排序等子句),你的两个Relation分别关联了不同表、选择了不同字段,因此触发兼容报错
解决方案
根据你的业务需求可以选择以下两种方案:
方案1:直接关联两张表(适用于需要同时获取两个关联表字段的场景)
不需要拆分两个Relation再合并,直接写一个同时左连两个关联的Relation即可,最终结果天然就是ActiveRecord::Relation类型:
companies = Company.select( "companies.company_code, event_contracts.company_name, event_plans.content" ).left_joins(:event_contracts, :event_plans)
如果你的两个原始Relation还有额外的过滤条件,可以直接在这个基础上链式调用where即可,也支持用or拼接同结构的过滤条件。
方案2:UNION合并结果集(适用于需要取两个Relation结果并集的场景)
如果你的两个Relation逻辑完全独立,确实需要合并两者的查询结果,可以先对齐两个Relation的select结构(字段数量、类型保持一致,缺省字段用NULL填充并起相同别名),再通过UNION拼接为子查询包装为Relation:
# 对齐两个Relation的select结构 relation_1_aligned = Company.select( "companies.company_code, event_contracts.company_name as val1, NULL as val2" ).left_joins(:event_contracts) relation_2_aligned = Company.select( "companies.company_code, NULL as val1, event_plans.content as val2" ).left_joins(:event_plans) # 拼接UNION SQL并包装为Relation union_sql = "(#{relation_1_aligned.to_sql}) UNION (#{relation_2_aligned.to_sql})" companies = Company.from("#{union_sql} as companies")
注意:如果不需要去重,可以把
UNION替换为UNION ALL获得更高的查询性能。
最终得到的companies都是可链式调用的ActiveRecord::Relation类型。
内容的提问来源于stack exchange,提问作者Pa Stay
相关产品推荐
相关产品推荐

