SQL оператор для преобразования jsonb ha sh в json строку - PullRequest
0 голосов
/ 17 июня 2020

У меня есть миграция данных rails (postgres db), где я должен использовать чистый sql для преобразования данных из-за некоторых ограничений модели. Данные хранятся как json в виде строки, но мне нужно, чтобы она была пригодной для использования ha sh для других целей.

Моя миграция работает так, чтобы преобразовать его в ha sh. Однако мой метод down просто удаляет данные или оставляет их как пустые {}. Кстати, чтобы устранить путаницу, мое имя столбца на самом деле сохраняется как data в таблице Games

На основе моего метода вверх, как мне правильно отменить миграцию, используя только 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

Вот как он выглядит после правильного преобразования

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

как это было до миграции и на что нужно откатиться:

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

1 Ответ

1 голос
/ 17 июня 2020

Если вы отображаете структуру данных в консоли rails, этих \" на самом деле там нет. Они просто форматируют, потому что консоль заключила строку в ". Например ...

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

Но если мы его напечатаем ...

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

Учитывая, что это строка JSON, вы можете просто изменить тип столбца на jsonb, и покончим с этим.

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

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

Postgres не знает, как автоматически преобразовать текст в jsonb, поэтому нам нужно сообщить об этом. using data::jsonb выполняет простое преобразование текста в jsonb. Он может отлично преобразовывать jsonb в текст.

Вы можете сделать это при миграции с помощью change_column.

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

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