Edited at

MongoDBからMySQLにレプリケーション

More than 1 year has passed since last update.

表題のことをするためのライブラリ「Momy」をアップデートしたので、忘れないうちに記事にしておこうと思います。(アップデートの内容は、テスト追加が主です)

MongoDBはNoSQLなドキュメントデータベースなので、基本スキーマを持ちません。ただ、CouchDBなどとは異なり「コレクション」の概念があります。なので、若干強引ですが、コレクションをSQLのテーブルにマッピングすれば、MongoDBからMySQLへの一方向リプリケーションは比較的簡単に実現できます。

ff85da46-c732-5794-b7b0-1f9d3fb9d231.png

MongoDBはそのままだと、Microsoft Accessほかのオフィス系のツールから繋ぎにくいですが、MySQLに移してしまえば、各種ツール、ドライバがあります。MongoDBからRDBにリプリケーションするツールとしては、現在2つのツールがあります。(他にもあるかも)

ライブラリ
レプリケーション
実装
説明

MoSQL
MongoDB → PostgreSQL
Ruby

Stripeが開発。残念ながら2年間メンテナンス停止状態。

Momy
MongoDB → MySQL
Node
去年、私がカッとなって作りました。

PostgreSQLを使う場合はMoSQLをどうぞ。あと、Apache Drillなども用途によっては選択肢に上がるかもしれません。


Momyのインストール

npmから入手できます。

$ npm install -g momy


スキーマ設定

スキーマレスとはいえ、実際にはアプリケーションが構造をある程度規定しているはずです。その「スキーマ」をmomyfile.jsonに設定します。基本的には、MongoDB(同期元)とMySQL(同期先)のデータベースを指定し、コレクションごとにフィールド名とその型を書いていけばOKです。

{

"src": "mongodb://localhost:27017/myapp",
"dist": "mysql://root@localhost:3306/myapp",
"collections": {
"contacts": {
"_id": "string",
"createdAt": "DATETIME",
"lastName": "string",
"firstName": "string",
"code": "number",
"birthday": "DATE",
"address.state": "string",
"address.city": "string",
"address.street": "string"
},
"meetings": {
"_id": "string",
"createdAt": "DATETIME",
"date": "DATE",
"title": "string",
"description": "TEXT"
}
}
}


データベースの指定

同期元のデータベースをsrcに、同期先のデータベースをdistに設定します。



  • "src": "mongodb://localhost:27017/myapp" 必ずMongoDBを指定


  • "dist": "mysql://root@localhost:3306/myapp" 必ずMySQLを指定

データベースのURLは、次の書式をとります。



  • データベースの種類://ユーザ名:パスワード@サーバ名:ポート/データベース名


コレクション

だいたい、見たままですが、詳しくはAPPENDIXをどうぞ。


MongoDBの下ごしらえ

Momyは、MongoDBのレプリカセットの情報を使います。そのため、standaloneモードのMongoDBだと、リプリケーションができません。次のように、レプリカセットをオンにして起動します。

$ mongod --replSet "rs0" --oplogSize 100

別のターミナルからmongoシェルを開き、レプリカセットを初期化(rs.initiate())しておきます。このコマンドは初回のみ実行してください。これで、レプリカセットがこのデータベースでアクティブになりました。

$ mongo

....
> rs.initiate()


実行する

初回実行時は、--importが必要です。

$ momy --config momyfile.json --import

このオプションをつけると、momyfile.jsonのスキーマの通り、MySQLのテーブルが作成され、MongoDB上の既存ドキュメントが、MySQLにコピーされます。

コピーが完了すると、その後はMongoDBを監視して、リアルタイムにMySQLに同期するようになります。終了する場合は、Ctl+Xを押します。

2回目以降は、

$ momy --config momyfile.json

だけでOKです。サーバなどで、確実に同期を実行し続けたい場合は、foreverがおすすめです。

$ forever momy --config momyfile.json

万が一、momyが落ちた場合も、立ち上げ直して実行を続けてくれます。


最後に

ライブラリ作成の経緯などは、昨年の記事をどうぞ。詳しい使い方についてはMomyのリポジトリも参考にしてください。それでは。


APPENDIX


コレクションの設定

momyfile.json上では、次のような書式で、コレクション名とフィールド設定をします。

{

"コレクション名": {
"_id": "string あるいは number",
"フィールド名1": "フィールドの型",
"フィールド名2": "フィールドの型",
...
}
}

_idは必須。MySQLに持って行く際にプライマリーキーになります。

フィールド名には.を使って、ネストした値を取得することもできます。例:



  • {a:{b:{c: 'Hey!'}}} というデータがあったら、a.b.cで'Hey!'を取得。


  • {address: {state: '東京', city: '世田谷', street: '代田'}} というデータがあったら、address.stateで'東京'を取得。


フィールドの型

型として、次のものが使えます。


  • BIGINT

  • DOUBLE

  • TINYINT

  • VARCHAR

  • DATE

  • DATETIME

  • TIME

  • TEXT

メモ: もし、足りない型があったらIssuePull Requestください。

エイリアスとして、次の表現も使えます。



  • string: VARCHARに同じ


  • number: DOUBLEに同じ


  • boolean: TINYINTに同じ


日付型

DATE型と、DATETIME型には、"2016-11-13"といった文字列のほか、タイムスタンプ(ミリ秒)を渡すこともできます。もし、DATEが指定されたとすると、MongoDB上の値が次のいずれであっても、MySQLに渡される値は"2016-11-13"となります。



  • "2016-11-13 01:14:28" (文字列)


  • "2016-11-13T01:14:28" (文字列)


  • "20161113T011428" (文字列)


  • 1478967268294 (数値)


数値型



  • BIGINTを指定した場合、小数点以下はparseInt()で丸められます。


  • DOUBLEを指定した場合、parseFloat()で解釈されます。


文字列型



  • VARCHARは、実際にはVARCHAR(255)です。255文字以上の場合は、トランケートされます。


  • TEXTには、明確な文字数制限がありません。