Rails Active Record - 从其他列值创建列

时间:2017-08-29 13:23:48

标签: ruby-on-rails database activerecord sqlite

假设我的数据库中有一个用户模型,每个用户的高度和重量已经输入。现在我想在用户表中添加一个BMI列,根据每个现有用户的权重和高度计算。如果我有一百万用户,那么最有效的方法是什么?

P.S

我尝试添加一个在调用时在本地运行脚本的rails路由,但发现它需要很长时间。我不认为我可以使用rails控制台,因为它需要一个复杂的方法。

3 个答案:

答案 0 :(得分:1)

你可以使用update_all,这个更新通过数据库NOT循环遍历所有记录 api documentation for update_all

User.update_all('bmi = height * weight')

答案 1 :(得分:0)

首先,您需要迁移才能添加列,但不要设置默认值(设置默认值可能需要很长时间才有大量记录)

add_column:some_attribute,:string

在列之后,您需要回填它。

使用find_each。无论您做什么,1,000,000名用户都需要一些时间来处理。使用find_each确保它们一次只能实例化1,000个。

User.find_each do |user|
  num = user.height * user.width # or whatever you need to figure out here
  user.update_attributes(some_attribute: num)
end 

您可以设置一个终结点find_each,但实际上,您最好通过控制台运行它。我使用screen,因为它有可能是一个长期运行的过程。

您可以将其放入迁移文件中,但对于是否在迁移中操纵数据的最佳做法存在不同的意见。

答案 2 :(得分:-1)

因此,如果您想为每个现有用户添加BMI,最好的方法是创建rake task,您可以在其中添加用于更新该列的逻辑。

假设您已将新列bmi添加到用户模型(整数),那么您需要rake任务:

namespace :user do
  task :bmi_calculator => 'environment' do
    User.find_each do |user|
      bmi = user.height/user.weight (I'm not sure about computation)
      user.update_attribute(bmi: bmi)
    end
  end
end

然后您可以随时运行此任务(rake user:bmi_calculator)!另外,我的建议是使用一些cron作业来完成这种任务,在午夜流量不是那么大的时候自动运行。

干杯