我正在尝试构建一个比较两个对象的查询,如果它们具有相同的id
,则不会获取该记录。我有这个:
@channels.each do |channel|
unless @guide_channels.where(:id => channel.id).exists?
@dropdown_channels = @dropdown_channels.where(:id => channel.id)
end
end
这会创建查询,但会在每个值之间放置一个AND,这不是我想到的。我想要“或”运算符。是否有一个'orwhere'函数我可以使用或者有更好的方法来使用一些比较函数吗?
答案 0 :(得分:1)
关键是.where()
对象的AR::Relation
方法将条件添加到一组条件中,然后AND
- 在执行查询时一起编写。
您需要做的是像NOT IN
这样的查询:
# select all the ids for related @guide_channels
# if @channels comes from a query (so it's a ActiveRecord::Relation):
guide_ids = @guide_channels.where(:id => @channels.pluck(:id)).pluck(:id)
# use .where(:id => @channels.map {|c| c.id}) instead if @channels is just an array
# then use the list to exclude results from the following.
@dropdown_channels = @dropdown_channels.where("id NOT IN (?)", guide_ids.to_a)
第一个查询将累积@guide_channels
中包含条目的频道的所有ID。第二个将使用第一个结果从下拉列表的结果中排除找到的通道。
答案 1 :(得分:0)
这种奇怪的行为是由ActiveRecord对范围的惰性评估引起的。 会发生什么是
行@dropdown_channels = @dropdown_channels.where(:id => channel.id)
在您实际使用@dropdown_channels
的值之前,不会向数据库发送查询,并且当您将所有条件连接成一个大查询时,这就是您在条件之间得到AND的原因。 / p>
为了强制ActiveRecord急切加载范围,您可以使用all
范围或first
范围,例如:
@dropdown_channels = @dropdown_channels.where(:id => channel.id).first
这会强制ActiveRecord立即计算返回结果的查询,而不是累积延迟评估的范围。
另一种方法可能是累积所有那些channels_ids,并在稍后的一个查询中获取它们,而不是对每个查询进行查询。这种方法与DB资源相关的成本效益更高。 为了实现这个目标:
dropdown_channels_ids = []
@channels.each do |channel|
unless @guide_channels.where(:id => channel.id).exists?
dropdown_channels_ids << channel.id
end
end
@dropdown_channels = @dropdown_channels.where(:id => dropdown_channels_ids)