最近、新旧のHerokuアプリ間でデータを移行する機会がありました。
当初は単純にリストアすればいいかと考えましたが、新旧間でテーブル構造などを変えたことに気づきました。
また、一部のテーブルのみのリストアができなくなったみたいで、ローカルのPostgreSQLへリストア・列変換後にHerokuにリストアという方法も取りにくくなりました。
Heroku PGBackups | Heroku Dev Center
そのため、直接Heroku Postgresに接続してデータ変換を行おうと考えました。良さそうなライブラリ(ORM)を探してみたところpeewee
があったため、試してみました。
coleifer/peewee - GitHub
環境
流れ
pwizによるModelの自動生成
peeweeを使う際、Modelを作成する必要があることから、peeweeのpwizを使ってModelを自動生成しました。
- HerokuのWebサイトにログインし、新旧のアプリのHeroku Postgresの接続情報を確認
- virtualenvをactivate
- コマンドラインから以下の内容でpwizを実行し、新旧のModelファイルを生成
python -m pwiz -e postgresql -u "user_name" -P "password" -H "host_name" "databasename" > "modelファイル名"
できあがったModelファイルは以下のような感じになりました。
before.py
from peewee import * database = PostgresqlDatabase(<your connection>) # 略 class Apples(BaseModel): created_at = DateTimeField() name = CharField(null=True) tweet = CharField(null=True) tweet_id = BigIntegerField(null=True) tweeted_at = DateTimeField(null=True) updated_at = DateTimeField() # 略 class Tweets(BaseModel): created_at = DateTimeField() last_searched = BigIntegerField(db_column='last_searched_id', null=True) updated_at = DateTimeField() class Meta: db_table = 'tweets'
after.py
from peewee import * database = PostgresqlDatabase(<your connection>) # 略 class TweetsTweets(BaseModel): name = CharField() tweet = CharField() tweet_id = BigIntegerField() tweeted_at = DateTimeField() class Meta: db_table = 'tweets_tweets' class TweetsLastsearch(BaseModel): prev_since = BigIntegerField(db_column='prev_since_id') class Meta: db_table = 'tweets_lastsearch'
新旧データ変換のスクリプトの作成
import traceback from before import database as before_db, Apples, Tweets from after import database as after_db, TweetsLastsearch, TweetsTweets def main(): '''新旧のテーブル移行処理''' try: with before_db.transaction(): tweets = Apples.select() last = Tweets.select() with after_db.transaction(): tweet_source = [convert_tweet(x) for x in tweets ] TweetsTweets.insert_many(tweet_source).execute() last_source = [{ 'prev_since': last[0].last_searched }] TweetsLastsearch.insert_many(last_source).execute() print('commit') except Exception: traceback.print_exc() print('error') def convert_tweet(tweets): '''新旧のテーブル列をマッピング''' return { 'name': tweets.name, 'tweet': tweets.tweet, 'tweet_id': tweets.tweet_id, 'tweeted_at': tweets.tweeted_at } if __name__ == '__main__': main()
あとは、Pythonスクリプトを実行し、pgAdminIIIなどで確認すると、無事にHerokuの新アプリへデータが移行されていました。
ソースコード
GitHubに上げました。
thinkAmi-sandbox/ringo_tabetter_migration
参考
テーブル構造が一致するなど、単純にリストアすればいいだけなら、以下の方法で良さそうでした。
herokuのデータベースをローカルにリストアする | Workabroad.jp