【Rails】herokuのPostgreSQLからdbseedに変換してMySQLに入れる

2018年5月15日

テックアカデミーのRailsプログラミングスクールに入門してカリキュラムに沿って進めていますが、開発環境(Cloud9)ではMySQLを使っていてherokuではpostgreSQLを使っています。

このため開発したアプリをherokuにデプロイして使うDBが異なるので、それが気持ち悪いなぁと。運用面でもあまりよくないと思うんですよねぇ。もし本番環境のherokuで不具合が出たらそれを開発環境で再現しないといけないと思うわけです。

なのでpostgreSQLのデータベースをmySQLでも使えるようにしたいと考えていました。

postgreSQLのデータをmySQLで使う案

案としては以下3つ

1.Cloud9にpostgreSQLをインストールする
2.開発環境の接続先DBをherokuのpostgreSQL(本番DBを複製して)にする
3.postgreSQLからバックアップしたデータをmySQL用に変換してインポートする

全て調べたり講師に質問したりしたものの今の自分の力量ではできそうもありません。講師にも

1はpostgreSQLのインストールはユーザー作成の部分が大変で躓くと思うと言われてるし。

2はデータが大量になるとあまり適していない、テストするぐらいならいいけど。それに課金も気にしなきゃいけない。都度都度ネットワークを介してpostgreSQLに接続に行くのはちょっと考えにくい。

3はこれが出来れば楽だったんですが変換ツールは無いし(誰か作って!)文字コードは違うし、WEBで調べても手作業で修正するやり方ぐらいしかない

ということで途方にくれてたんですけど、次の方法でなんとかできました。

→postgreSQLから吐き出した全テーブルのINSERT文をrailsのdb/seed.rb用に変換してrailsでseedコマンドで流す

なんでこんな面倒なことになってるんだろう。たぶんもっと楽な方法あるんだろうけど。。

そもそもテックアカデミーの教材が最初からCloud9にpostgreSQLを使えるようにしといてくれればよかったのに。(●`ε´●)

てことで、誰の参考になるかわからないけど(っていうかならないだろうけど)やり方を残しておきます。

<環境>

開発環境:Cloud9 mySQL
本番環境:heroku postgreSQL

開発環境のmySQLには既にテーブルまで作成してある状態。だからデータだけINSERT出来れば良い。

Cloud9のターミナル上から作業。

pg_dumpコマンドでherokuのpostgreSQLデータを吐き出す

●まずはローカルからpostgreSQLのDB接続情報を得る

Cloud9のターミナルからプロジェクトのディレクトリにcdで移動して以下のコマンドを実行

$ heroku pg:credentials:url –app herokuのアプリ名
Connection information for default credential.
Connection info string:
“dbname=xxxxxxxxxxxxxxx host=ec2-com.amazonaws.com port=5432 user=uuuuuuuuuu password=pppppppppp sslmode=require”
Connection URL:
postgres://ユーザ名:パスワード@ホスト名:5432/データベース名

この情報をもとにコマンドを作る

●次にpg_dumpのコマンドを記述

$ pg_dump -d データベース名 -h ec2-xxxxxx.amazonaws.com -U ユーザ名 –data-only –inserts -W > insert.sql

これをcloud9のターミナルから打つので以下のようにする。

$ heroku run pg_dump -d データベース名 -h ec2-xxxxxx.amazonaws.com -U ユーザ名 –data-only –inserts -W > insert.sql

これでパスワードを求められる(画面上は何も出ない)ので、パスワードを入力してエンター。そうするとプロジェクトのルートフォルダにinsert.sqlというファイルが生成される。

pg_dumpで吐き出したデータをdb:seed用に形成

insert.sqlをローカルPCにダウンロードしておき、エディターで編集する。

●ファイルの中身からINSERT文以外を削除
–で始まるコメント文とか、SELECT文とか、schema_migrationsとかの行を全部削除。データが関係するINSERT文だけのこす。

●railsのdb:seedで扱える形に手で整形

db:seedコマンドでINSERT文を入れてくれたら良かったんですけど、このままじゃDBにINSERTできませんでした。だからcreate文を使うように編集しました。

例えば

INSERT INTO public.cities VALUES (1, ‘北海道’, ‘札幌市’, ‘2018-05-01 04:57:55.973977’, ‘2018-05-01 04:57:55.973977’);

目指すのはこんな形

City.create(id:1,pref: ‘北海道’,city: ‘札幌市’,created_at: ‘2018-05-01 04:57:55.973977’,updated_at: ‘2018-05-01 04:57:55.973977’)

●エクセルで整形するための準備

INSERT文をエディタで開いて、

INSERT INTO public.cities VALUES (1, ‘北海道’, ‘札幌市’, ‘2018-05-01 04:57:55.973977’, ‘2018-05-01 04:57:55.973977′);
をタブ区切りで以下のように置換

コンマをタブに置換、最初の(を(タブに置換、最後の)をタブ)に置換

INSERT INTO public.cities VALUES (\t1\t’北海道’\t’札幌市’\t’2018-05-01 04:57:55.973977’\t’2018-05-01 04:57:55.973977’);

このファイルを.csv形式で保存してエクセルで開くと

になる。

各列にカラム名をシンボル形式で記入。使うのはこの列だけなので。

右側にエクセルで文字列を連結。(クリック拡大)


こうなる

これをレコードの数だけコピー。これでrails db:seed用のcreate文を作成できました。

seed.rbファイルに記述してdb:seedコマンド実行

これをコピーしてdb/seed.rbファイルにペースト。

Cloud9のコンソールで

$ rails db:seed

を実行すればモデルを生成してコミットしていってくれます。rails cで、City.allや、City.all.countで入っていることを確認して完了。

※INSERT文に「NULL」という値があったら、これはRails用の「nil」に変更しておかないと駄目でした。

これを全てのテーブルで行いました。かなり面倒で手間です。

けど、これでpostgreSQLのデータをmySQLへ入れることができました。かなり力技のような気がしますけどRails3ヶ月の自分にとってはこのやり方がもっとも理解でき、リスクの少ないやりかたとなりました。=3