【问题标题】:Rails: batched attribute queries using ARELRails:使用 AREL 进行批量属性查询
【发布时间】:2013-03-21 15:27:47
【问题描述】:

我想使用find_in_batches 之类的东西,但不是对完全实例化的 AR 对象进行分组,而是对某个属性进行分组,比如 id。所以,基本上,混合使用find_in_batchespluck

Cars.where(:engine => "Turbo").pluck(:id).find_in_batches do |ids|
  puts ids
end

# [1, 2, 3....]
# ...

有没有办法做到这一点(可能与 Arel 一起),而不必自己编写 OFFSET/LIMIT 逻辑或重复分页宝石,如分页或 kaminari?

【问题讨论】:

    标签: sql ruby-on-rails activerecord arel


    【解决方案1】:

    这不是理想的解决方案,但这是一种仅复制粘贴大部分 find_in_batches 但产生关系而不是记录数组(未经测试)的方法 - 只需将其猴子修补到 Relation 中:

    def in_batches( options = {} )
      relation = self
    
      unless arel.orders.blank? && arel.taken.blank?
        ActiveRecord::Base.logger.warn("Scoped order and limit are ignored, it's forced to be batch order and batch size")
      end
    
      if (finder_options = options.except(:start, :batch_size)).present?
        raise "You can't specify an order, it's forced to be #{batch_order}" if options[:order].present?
        raise "You can't specify a limit, it's forced to be the batch_size"  if options[:limit].present?
    
        relation = apply_finder_options(finder_options)
      end
    
      start = options.delete(:start)
      batch_size = options.delete(:batch_size) || 1000
    
      relation = relation.reorder(batch_order).limit(batch_size)
      relation = start ? relation.where(table[primary_key].gteq(start)) : relation
    
      while ( size = relation.size ) > 0    
    
        yield relation
    
        break if size < batch_size
    
        primary_key_offset = relation.last.id
        if primary_key_offset
          relation = relation.where(table[primary_key].gt(primary_key_offset))
        else
          raise "Primary key not included in the custom select clause"
        end
      end
    end
    

    有了这个,你应该可以做到:

    Cars.where(:engine => "Turbo").in_batches do |relation|
      relation.pluck(:id)
    end
    

    这可能不是最好的实现(尤其是关于primary_key_offset 计算,它会实例化一条记录),但你明白了。

    【讨论】:

    • 确实是一次不错的尝试。但我更喜欢非猴子修补解决方案,因为我想将上述逻辑应用到可以由多个项目分发的库中,并且我希望尽可能减少对 AR 中代码注入的干扰.
    • 好点...所以让它成为一个类方法。我猜你的库无论如何都会包含在模型中,只要使用 AR,它就应该可以正常工作。
    • 最终使用 .limit 和 .offset ARel 方法。我只是说,为 Rails 提供这样一个开箱即用的解决方案真是太好了。
    • @ChuckE 你应该发布你的代码作为答案。我很想看看你想出了什么。
    猜你喜欢
    • 2011-05-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-25
    • 2011-07-01
    相关资源
    最近更新 更多