在哈希表中重命名特定的键

5

我有一个名为car_details的列,其中包含2000个条目,每个条目都是一个信息哈希,看起来像这样:

{"capacity"=>"0",
 "wheels"=>"6",
 "weight"=>"3000",
 "engine_type"=>"Diesel",
 "horsepower"=>"350",
 "fuel_capacity"=>"35",
 "fuel_consumption"=>"30"}

有些汽车的细节更多,有些则更少。我想将每辆有 "fuel_consumption" 键的汽车都改名为 "mpg"


1
这个 column 在数据库中吗?(即,这个哈希值是否已序列化?)还是你只是在内存中进行操作? - Kyle d'Oliveira
它在数据库中,是一个具有无关键访问的哈希表。 - Ashbury
3个回答

2

@Ivan Shamatov发布的答案非常有效,尤其对于处理大型数据库时要保持良好的性能。

我在PostgreSQL数据库上尝试了它,在jsonb列上。 为了让它正常工作,我们必须同样注意数据类型转换。

例如,在像这样的User模型上:

User < ActiveRecord::Base {
                   :id => :integer,
           :created_at => :datetime,
           :updated_at => :datetime,
                :email => :string,
           :first_name => :string,
            :last_name => :string,
          :custom_data => :jsonb
}

我的目标是重命名 custom_data jsonb 字段内的一个键。 例如,从以下 custom_data 哈希内容中:

{
                "foo" => "bar",
           "date" => "1980-07-10"
}

to:

{
                "new_foo" => "bar",
             "date" => "1980-07-10"
}

针对我数据库中的所有用户记录,我们可以执行以下查询:

old_key = 'foo'
new_key = 'new_foo'    
User.update_all("custom_data = REPLACE(custom_data::text, '#{old_key}'::text, '#{new_key}'::text)::jsonb")

这将仅替换我们的jsonb哈希中的目标键(old_key),而不更改哈希值或其他哈希键。
请注意,::text和::jsonb类型转换!

2

好的,前面的答案会生成2000个请求,但是你可以使用REPLACE函数来代替。MySQL和PostgreSQL都有这个函数,所以代码应该长成这样:

Car.update_all("car_details = REPLACE(car_details, 'fuel_consumption', 'mpg')")

请查看update_all方法的条件。
另请参阅PostgreSQL字符串函数MySQL字符串函数

我刚在我的本地mysql数据库上检查了这个查询,有480,000行数据,查询用了14秒钟。 - Ivan Shamatov
你会传递哪些选项来跳过没有fuel_consumption键的car_details? - Ashbury
好的,它不会更新根本不包含fuel_consumption的行,因此您不需要任何其他条件。 - Ivan Shamatov
根据您的数据集,这可能不太可能,但如果哈希的任何其他部分(键或值)包含“fuel_consumption”,则此命令也会将其重命名为“mpg”。 - Ollie Bennett

1
据我所知,使用原始 SQL 批量更新数据表中的序列化列并不容易。我能想到的最好方法是执行以下操作:
Car.find_each do |car|
  mpg = car.car_details.delete("fuel_consumption")
  car.car_details["mpg"] = mpg if mpg
  car.save
end

假设您正在使用Active Record,且您的模型名为"Car"。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接