我需要将模型记录分为两类inc and dec
:
我首先过滤我的记录,如下所示:
Model.where.not('first_value = 0 AND second_value = 0')
.where.not('first_value = second_value')
所以我可以写范围。
scope :filter -> do
where.not('first_value = 0 AND second_value = 0')
.where.not('first_value = second_value')
end
获得过滤结果后,我需要将记录分为两部分。
Increased; Decreased
但问题是我不知道如何添加这个条件来过滤我的结果,(一个解决方案可以循环遍历每个过滤的记录,并返回一个带有两个数组的哈希{{1} }和inc
一个,每个数组都包含dec
),它会像这样工作,但我认为解决方案不是最好的。
id of the record
如何过滤记录,因此当用户选择增加时,只会显示增加的记录;或者相反。
[更新]我现在的表现如何:
if first_value == 0 || second_value == 0
first_value > second_value ? increased : decreased
else
first_value > second_value ? decreased : increased
end
然后根据传递的参数,我重新加载模型def compare
records = self.reduce // the scope from above
ids = {inc: [], dec: []}
records.each do |r|
if r.first_value == 0 || second_value == 0
r.first_position > second_value ? ids[:inc] << r.keyword_id : ids[:dec] << r.keyword_id
else
r.first_position > second_value ? ids[:dec] << r.keyword_id : ids[:inc] << r.keyword_id
end
end
ids
end
或where(keyword_id: ids[:inc])
答案 0 :(得分:2)
鉴于你在这里提出的逻辑:
if first_value == 0 || second_value == 0
first_value > second_value ? increased : decreased
else
first_value > second_value ? decreased : increased
end
您可以按如下方式编写范围:
scope :increased -> do
where("((first_value = 0 or second_value = 0) and (first_value > second_value)) or ((first_value != 0 and second_value != 0) and (first_value <= second_value))")
end
scope :decreased -> do
where("((first_value = 0 or second_value = 0) and (first_value <= second_value)) or ((first_value != 0 and second_value != 0) and (first_value > second_value))")
end
这可以清理一下,但应该按原样运行。
答案 1 :(得分:1)
scope :filtered -> do
where.not('first_value = 0 AND second_value = 0')
.where.not('first_value = second_value')
end
scope :increased -> do
filtered.where('first_value < second_value')
end
scope :decreased -> do
filtered.where('first_value > second_value')
end
然后,Model.increased将返回已增加的所有已过滤记录。
这有帮助吗?
编辑:
scope :increased -> do
User.where("(first_value = 0 or second_value = 0 and first_value > second_value) or (first_value < second_value)")
end
答案 2 :(得分:1)
这是我对如何将条件代码从ruby传递给sql的看法,因此您可以在对数据库的单个查询中拥有increased
或decreased
个集合。
请注意,在第一个过滤器中,条件where.not('first_value = 0 AND second_value = 0')
是多余的,因为您已经过滤掉两列上具有相同值的行:
scope :filter, -> do
where.not("first_value = second_value")
end
scope :inc, -> do
query = <<-SQL
((first_value = 0 OR second_value = 0) AND first_value > second_value)
OR
((first_value != 0 AND second_value != 0) AND first_value < second_value)
SQL
filter.where(query)
end
scope :dec, -> do
query = <<-SQL
((first_value = 0 OR second_value = 0) AND first_value < second_value)
OR
((first_value != 0 AND second_value != 0) AND first_value > second_value)
SQL
filter.where(query)
end
你可以重构很多重复。
话虽如此,你说一个范围“增加”是有点误导性的。并且它返回此值(first: 2, second: 5)
以及(first: 3, second: 0)
。减少&#39;同样的事情范围。我知道这个问题是对您的实际业务案例的简化,但仍然要小心:)
答案 3 :(得分:1)
如果您通过添加额外的increased
booelan字段来对数据库进行非规范化并通过回调更新它,我认为您可以大大简化您的问题。
示例:
before_save :set_increased
def set_increased
self.increased = first_value < second_value
end
通过这种方式,您可以将increased
或decreased
范围链接到过滤器
scope :increased -> { where(increased: true) }
scope :decreased -> { where(increased: false) }
这是最简单的方法。如果您将其展开以在回调中集成您的确切查询需求,您将最终只使用该过滤器。考虑到这一点,为新字段添加索引将有更多帮助。
如果如评论中所述,您需要3个比较(1,2),(2,3),(3,4),那么我认为您可以扩展上述技术并使用其索引创建3个额外列(如果需要)并相应地修改模型回调逻辑。
现在,如果您想要更复杂的东西(例如,对4个(或更多)字段进行随机比较),最好保持模型清洁并创建一个包装器模块来处理查询生成器。也许使用一个小型DSL。