过滤模型中的记录

时间:2014-07-16 13:56:53

标签: ruby-on-rails ruby activerecord

我需要将模型记录分为两类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])

4 个答案:

答案 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的看法,因此您可以在对数据库的单个查询中拥有increaseddecreased个集合。

请注意,在第一个过滤器中,条件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

通过这种方式,您可以将increaseddecreased范围链接到过滤器

scope :increased -> { where(increased: true) }
scope :decreased -> { where(increased: false) }

这是最简单的方法。如果您将其展开以在回调中集成您的确切查询需求,您将最终只使用该过滤器。考虑到这一点,为新字段添加索引将有更多帮助。

更新

如果如评论中所述,您需要3个比较(1,2),(2,3),(3,4),那么我认为您可以扩展上述技术并使用其索引创建3个额外列(如果需要)并相应地修改模型回调逻辑。

现在,如果您想要更复杂的东西(例如,对4个(或更多)字段进行随机比较),最好保持模型清洁并创建一个包装器模块来处理查询生成器。也许使用一个小型DSL。