【问题标题】:Rails Active Record - Creating a column from other column valuesRails Active Record - 从其他列值创建列
【发布时间】:2017-08-29 13:23:48
【问题描述】:

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

附言

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

【问题讨论】:

  • 您想要数据库中的实际列,只计算迁移数据,还是只想要模型上的只读属性?
  • @Ilya 绝对不是,这解释了如何批量运行更新,我想知道如何根据其他列的值创建列。
  • @Isaac,您可以创建一个列,然后批量更新所有值。

标签: ruby-on-rails database activerecord sqlite


【解决方案1】:

您可以使用 update_all,此更新通过数据库而不是循环所有记录 api documentation for update_all

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

【讨论】:

    【解决方案2】:

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

    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,因为它有可能成为一个长期运行的过程。

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

    【讨论】:

      【解决方案3】:

      因此,如果您想为每个现有用户添加 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 作业来执行此类任务,以便在午夜后流量不大时自动运行。

      干杯

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-01-25
        • 1970-01-01
        • 1970-01-01
        • 2013-09-20
        相关资源
        最近更新 更多