25
Help us understand the problem. What are the problem?

More than 5 years have passed since last update.

posted at

updated at

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

表題のことをするためのライブラリ「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には、明確な文字数制限がありません。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Sign upLogin
25
Help us understand the problem. What are the problem?