我需要批量更新数千条记录,并且我希望批量处理这些更新。首先,我尝试了:
Foo.where(bar: 'bar').find_in_batches.update_all(bar: 'baz')
我希望...which能生成这样的语句:
"UPDATE foo SET bar = 'baz' where bar='bar' AND id > (whatever id is passed in by find_in_batches)"
这不起作用,因为find_in_batches返回一个数组,而update_all需要一个ActiveRecord关系。
这是我接下来尝试的:
Foo.where(bar: 'bar').select('id').find_in_batches do |foos|
ids = foos.map(&:id)
Foo.where(id: ids).update_all(bar: 'baz')
end
这是可行的,但显然它先运行select,然后运行update,而不是基于我的“where”条件进行单次更新。有没有办法清理这一点,这样select和update就不必是单独的查询了?
发布于 2016-09-22 15:32:17
在Rails5中,有一个新的方便的方法ActiveRecord::Relation#in_batches
来解决这个问题:
Foo.in_batches.update_all(bar: 'baz')
有关详细信息,请查看documentation。
发布于 2015-02-12 00:35:59
pdobb的答案是正确的,但在Rails 3.2.21中不适用于我,因为这个问题是ActiveRecord不能解析带有更新调用的偏移:
https://github.com/rails/rails/issues/10849
我相应地修改了代码,它可以很好地同时在我的Postgres表上设置默认值:
batch_size = 1000
0.step(Foo.count, batch_size).each do |offset|
Foo.where('id > ? AND id <= ?', offset, offset + batch_size).
order(:id).
update_all(foo: 'bar')
end
发布于 2017-08-17 01:56:11
我还没有机会测试这一点,但是你也许可以使用ARel和子查询。
Foo.where(bar: 'bar').select('id').find_in_batches do |foos|
Foo.where( Foo.arel_table[ :id ].in( foos.to_arel ) ).update_all(bar: 'baz')
end
https://stackoverflow.com/questions/23252811
复制相似问题