我目前有以下数据库架构:
create_table :user_actions do |t|
t.integer :emitter_id
t.string :emitter_type
t.integer :target_id
t.string :target_type
t.json :payload
t.timestamps
end
我想将payload
字段从json
迁移到hstore
。
执行以下操作:
change_column :user_actions, :payload, :hstore
导致以下错误消息:
PG::DatatypeMismatch: ERROR: column "payload" cannot be cast automatically to type hstore
HINT: Specify a USING expression to perform the conversion.
不确定如何使用USING
提示以及在不丢失任何数据的情况下执行此迁移的最佳方法是什么?
答案 0 :(得分:11)
提示:指定USING表达式以执行转换
实际上格式为:
change_column :user_actions, :payload, '[type_to_which_you_want_to_change] USING CAST(data AS [type_to_which_you_want_to_change])'
所以在你的情况下:
change_column :user_actions, :payload, 'hstore USING CAST(payload AS hstore)'
<强>参考:强>
答案 1 :(得分:2)
Taimoor Changaiz的答案部分不正确,因为postgresql无法在不使用自定义函数的情况下将JSON强制转换为HSTORE。假设您的JSON没有嵌套,那么这将起作用:
def self.up
execute <<-SQL
CREATE OR REPLACE FUNCTION my_json_to_hstore(json)
RETURNS hstore
IMMUTABLE
STRICT
LANGUAGE sql
AS $func$
SELECT hstore(array_agg(key), array_agg(value))
FROM json_each_text($1)
$func$;
SQL
change_column :user_actions, :payload, 'hstore USING my_json_to_hstore(payload)'
end
def self.down
change_column :user_actions, :payload, 'json USING CAST(payload AS json)'
execute "DROP FUNCTION my_json_to_hstore(json)"
end
在这里感谢pozs的自定义postgresql函数:Casting JSON to HSTORE in Postgres 9.3+?
答案 2 :(得分:1)
寻求一个简单但有效的解决方案。创建一个名为parameters
的新列并执行一个简单的迁移脚本:
def up
add_column :user_actions, :parameters, :hstore
UserAction.find_each do |o|
o.parameters = o.payload
o.save!
end
remove_column :user_actions, :payload
end
def down
add_column :user_actions, :payload, :json
UserAction.find_each do |o|
o.payload = o.parameters
o.save!
end
remove_column :user_actions, :parameters
end