简体   繁体   English

SQL 语句将 jsonb hash 转换为 json 字符串

[英]SQL statement to convert jsonb hash to json string

I have a rails data migration (postgres db) where I have to use pure sql to convert the data due to some model restrictions.我有一个 Rails 数据迁移(postgres db),由于某些 model 限制,我必须使用纯 sql 来转换数据。 The data is stored as json as a string, but I need it to be a usable hash for other purposes.数据存储为 json 作为字符串,但我需要它是一个可用的 hash 用于其他目的。

My migration works to convert it to the hash.我的迁移工作将其转换为 hash。 However, my down method ends up just deleting the data or leaving it as an empty {}.但是,我的 down 方法最终只是删除数据或将其保留为空 {}。 Btw to clear up any confusion, my column name is actually saved as data in table Games顺便说一句,为了消除任何混淆,我的列名实际上保存为表格Games中的data

Based on my up method, how would i properly reverse the migration using sql only?根据我的 up 方法,我将如何仅使用 sql 正确逆转迁移?

class ConvertGamesDataToJson < ActiveRecord::Migration[6.0]
  def up
    statement = <<~SQL
      update games set data = regexp_replace(trim(both '"' from data::text), '\\\\"', '"', 'g')::jsonb;
    SQL

    ActiveRecord::Base.connection.execute(statement)
    # this part works!
  end

  def down
    statement = <<~SQL
      update games set data = to_json(data::text)::jsonb;
    SQL

    ActiveRecord::Base.connection.execute(statement)
  end
end

Here is how the it looks after properly converting it这是正确转换后的样子

data: {
  "id"=>"d092a-f2323",
  "recent"=>'yes',
  "note"=>"some text",
  "order"=>1
}

how it is before the migration and what it needs to rollback to:迁移之前的情况以及需要回滚到的内容:

data: 
  "{
    \"id\":\"d092a-f2323\",
    \"recent\":\"yes\",
    \"note\":\"some text\",
    \"order\":1,
  }"

If you're displaying a data structure in the rails console, those \" aren't really there. They're just formatting because the console has wrapped the string in " .如果您在 Rails 控制台中显示数据结构,那些\"并不真正存在。它们只是格式化,因为控制台已将字符串包装在"中。 For example...例如...

[2] pry(main)> %{"up": "down"}
=> "\"up\": \"down\""

But if we print it...但是如果我们打印它...

[3] pry(main)> puts %{"up": "down"}
"up": "down"

Given that is a JSON string, you can simply change the type of the column to jsonb and be done with it.鉴于这是一个 JSON 字符串,您可以简单地将列的类型更改为 jsonb 并完成它。

-- up
alter table games alter column data type jsonb USING data::jsonb;

-- down
alter table games alter column data type text;

Postgres doesn't know how to automatically cast text to jsonb, so we need to tell it. Postgres 不知道如何自动将文本转换为 jsonb,所以我们需要告诉它。 using data::jsonb does a simple cast of the text to jsonb. using data::jsonb将文本简单地转换为 jsonb。 It can cast jsonb to text just fine.它可以将 jsonb 转换为文本就好了。

You can do this in a migration with change_column .您可以使用change_column在迁移中执行此操作

def up
  change_column :users, :data, :jsonb, using: 'data::jsonb'
end

def down
  change_column :users, :data, :text
end

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM