我有一列car_details
,其中包含2000个条目,每个条目都是如下所示的信息哈希:
{"capacity"=>"0",
"wheels"=>"6",
"weight"=>"3000",
"engine_type"=>"Diesel",
"horsepower"=>"350",
"fuel_capacity"=>"35",
"fuel_consumption"=>"30"}
有些车的细节更多,有些车的细节更少。我想在每辆有该钥匙的汽车上将"fuel_consumption"
钥匙重命名为"mpg"
。
据我所知,没有一种简单的方法可以用原始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,并且您的模型称为“汽车”。
嗯,先前的答案将生成2000个请求,但是您可以改用REPLACE
函数。 MySQL和PostgreSQL都有,所以就像:
Car.update_all("car_details = REPLACE(car_details, 'fuel_consumption', 'mpg')")
查看条件的update_all
方法。
另请参见update_all
和PostgreSQL string functions。
@ Ivan Shamatov发布的答案非常好,对于在大型数据库上表现出色尤其重要。
我在jsonb列上的PostgreSQL数据库中尝试过。为了使其工作,我们必须同样注意数据类型转换。
例如,在像这样的MySQL string functions模型上:
User
我的目标是在User < ActiveRecord::Base {
:id => :integer,
:created_at => :datetime,
:updated_at => :datetime,
:email => :string,
:first_name => :string,
:last_name => :string,
:custom_data => :jsonb
}
jsonb字段内重命名密钥。例如custom_data
哈希来自以下内容:
custom_data
至:
{
"foo" => "bar",
"date" => "1980-07-10"
}
对于所有用户记录存在于我的数据库中。
我们可以执行此查询:
{
"new_foo" => "bar",
"date" => "1980-07-10"
}
这只会替换jsonb哈希中的目标键(old_key),而不会更改哈希值或其他哈希键。
注意old_key = 'foo'
new_key = 'new_foo'
User.all.update_all("custom_data = REPLACE(custom_data::text, '#{old_key}'::text, '#{new_key}'::text)::jsonb")
和::text
类型转换!