Ruby on Rails更好的方式来执行选择

时间:2016-07-26 08:39:39

标签: ruby-on-rails ruby

我有这样的代码只能获得用户青睐的产品。

@products = current_user.products.select {|product| product.count_favourited > 0 }

如果用户拥有大量产品,此代码将使用大量内存。问题是,我无法对查询执行过滤,因为赞成产品的用户数量存储在Redis上。

喜欢

def count_favourited
  $redis.scard("some_key_based_on_product_id")
end

还有其他方法可以达到这个目的吗?

如何在内部使用find_each呢?它将使用批处理?

@products = []
current_user.products.find_each do |product|
  @products << product if product.count_favourited > 0
end

3 个答案:

答案 0 :(得分:0)

怎么样:

current_user.products.where("products.count_favourited > 0")

或使用范围:

class Product < ActiveRecord::Base 
  scope :favourited, -> { where("count_favourited > 0") }
end

current_user.products.favourited

我错过了什么或者只是这么简单吗?

答案 1 :(得分:0)

我担心我对redis不太了解,但如果你主要担心的是内存使用,我会想到两个想法。首先,如果我正确地推断您在redis中使用了Set,那么sscan可能会有所帮助。至于Rails解决方案:

@products = current_user.products.keep_if {|product| product.count_favourited > 0 }

如果current_user.products返回产品列表的副本,那么对所述副本进行就地修改应该是安全的。 keep_if将做到这一点,从而避免为select做一个额外的副本所涉及的时间和记忆(当然,这是以就地操作所需的时间为代价)。

答案 2 :(得分:0)

  

如何在内部使用find_each,它将使用批处理?

是的,如果您只关心内存使用情况(而不是执行速度),那么批处理将解决您的问题。减少内存使用量正是它的用途(并没有带来任何其他好处)。

你可以反过来做吗?即,请redis为您提供用户喜欢的产品ID?我想我能猜到答案......