MongoDBからMySQLへのEmbulkを使った移行

# はじめに
[CYBIRD Advent Calendar 2023](https://qiita.com/advent-calendar/2023/cybird) 11日目担当の @cy_yusuke_ito です。
10日目は@moffunnyaさんの記事でした。なかなか興味深い内容でしたので、皆さんも是非見てみて下さい。

# 概要
MongoDBからMySQLへのデータ移行を[Embulk](https://github.com/embulk/embulk)を使用して実施したので、その方法をまとめていこうかと思います。

# そもそもNoSQLとは？MongoDBとは？
いきなりMongoDBといわれてもよくわからないと思いますので、簡単にですが説明します。

まず、MongoDBはNoSQLというデータベースの1つとなります。
NoSQLは、MySQLやMariaDBといったリレーショナルデータベース（RDB）とは異なる方法でデータを処理・操作するデータベースの総称です。

MongoDBは、NoSQLのデータベースの中では世界中で最も広く活用されているものの1つです。NoSQLの種類の中ではドキュメント指向型データベースといわれ、データを「ドキュメント」といわれるJSONに類似した形式で格納して管理しています。
(より詳しいNoSQLとSQLの説明は、ぜひ君の手で調べてくれ！)

MongoDBには、以下のようにデータが格納されています。今回、このデータをもとに作業内容を記載していきます。
```
{ "_id" : ObjectId("d1924b93b5b180c26"), "user_id" : "60523899", "event_id" : [ 12-34 ] }
{ "_id" : ObjectId("91a24b93b4ae8a6b0"), "user_id" : "3f2dca9a", "event_id" : [ 12-34 ] }
{ "_id" : ObjectId("a1924b9195b180c26"), "user_id" : "3ed4938b", "event_id" : [ 12-34 ] }
{ "_id" : ObjectId("a1924b9075b180c26"), "user_id" : "96f320c7", "event_id" : [ 12-34 ] }
{ "_id" : ObjectId("71a24b9694ae8a6b0"), "user_id" : "1cf4d39e", "event_id" : [ 12-34 ] }
{ "_id" : ObjectId("81924b9355b180c26"), "user_id" : "2477fb80", "event_id" : [ 12-34 ] }
{ "_id" : ObjectId("b1a24b94b4ae8a6b0"), "user_id" : "b68aa077", "event_id" : [ 12-34 ] }
```

# Embulkについて
今回の移行には、[Embulk](https://github.com/embulk/embulk)というツールを使用します。
Embulkは、様々なストレージ、データベース、NoSQL、クラウドサービス間のデータ転送を支援するツールで、様々なシチュエーションで使用できます。
各種拡張プラグインがありますが、今回は [input-mongodb] と [output-mysql plugin] の2つを使用していきます。

# 移行要件
移行要件は以下となります。
・移行元はMongoDB2.6.5、移行先はAurora MySQL8.0.mysql_aurora.3.04.0
・MySQLのカラム名は基本的にMongoDBのフィールド名であること
・任意のデータのみ移行する(移行しないフィールドがある)
・MongoDB のデータはフィールド数がまちまち
・MySQLで NOT NULL としたいカラムに対し、MongoDB で Key が存在しないデータの場合デフォルト値を指定して移行
★なるべく作業は自動化していきたい！！

# MongoDBからMySQLへ移行
## Embulkのインストール
1\. Javaインストール 
EmbulkはJavaで動くので、以下のコマンドでインストールします。
```
# sudo yum install -y java-1.8.0-openjdk
# java -version
```

2\. Embulkのインストール 
インストールし、サーバ内でのパスを通していきます。

```
# wget https://github.com/embulk/embulk/releases/download/v0.9.25/embulk-0.9.25.jar -O embulk.jar
# mv embulk.jar /usr/local/bin/embulk
# chmod +x /usr/local/bin/embulk
# export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64
# export PATH="$JAVA_HOME/bin:$PATH"
# export PATH="$HOME/.embulk/bin:$PATH"
# source ~/.bashrc
```

3\. プラグインの導入
今回、移行するにあたり必要なプラグインを導入していきます。
```
$ embulk gem install embulk-input-mongodb
$ embulk gem install embulk-output-mysql
$ embulk gem install embulk-filter-expand_json
$ embulk gem install embulk-filter-column
```

どのようなプラグインなのかを簡単に説明しますと、以下のようになります。

・[embulk-input-mongodb](https://github.com/embulk/embulk-input-mongodb)：MongoDBからデータを呼び出す
・[embulk-output-mysql](https://github.com/embulk/embulk-output-jdbc/tree/master/embulk-output-mysql)：MySQLへデータを送る
・[embulk-filter-expand_json](https://github.com/embulk/embulk-filter-expand_json)：MongoDBはjson形式のため、読み込んだデータをSQL形式に展開する。
・[embulk-filter-column](https://github.com/embulk/embulk-filter-column)：空のカラムにNULLではなく、空欄などのデフォルト値を設定して入れる。

## MongoDB→MySQL作業
ここまで移行のためのツールは準備していきました。
記載していませんが移行先のMySQLには、あらかじめデータ投入先のデータベースおよびテーブルを作っておくと便利です。
ここからは移行作業を行っていきます。

1\. Embulkのコンフィグファイル(config.yml)を作成する。
　移行時の処理内容を記載したコンフィグを作成します。
　ファイル名は任意ですが、必ず<b>ymlファイル</b>で作成してください。

```config.yml
in:
  type: mongodb
  hosts:
  - {host: MongoDBのホスト名orIPアドレス, port: ポート番号}
  database: DB名
  collection: "コレクション名"

#以下は、MongoDB内の移行したいフィールドや移行先でのデータの扱いを記載しています。
#記載例では、カラム名、データタイプ、デフォルト、リネームの処理を記載しています。
filters:
  - type: expand_json
    json_column_name: record
    expanded_columns:
      - {name: フィールド名, type: データタイプ(多くはlongかstring)}
      - {name: user_id, type: string}
  - type: column
    columns:
       - {name: id}
       - {name: user_id}
       - {name: event_id, default: '12-34'}
  - type: rename
    columns:
      event_id: Event_ids
      
#ここからは移行先のMySQLの情報を記載していきます。
out:
  type: mysql
  host: 移行先MySQLのホスト名orIPアドレス
  port: ポート番号
  user: ユーザー名
  password: パスワード
  database: DB名
  table: テーブル名
#ここからはテーブル定義等を載せていきます。基本、create_tableコマンドと同じように記載していきます。
  create_table_constraint: 'PRIMARY KEY (`id`)'
  column_options:
    id: {type: 'int(11) NOT NULL auto_increment comment "ID"'}
    user_id: {type: 'int(11) NOT NULL comment "ユーザーID"'}
    Event_ids: {type(1): 'int(11) NOT NULL comment  "イベントID"'}
#以下のmodeはデータの投入方法について指定しています。replace(作り直し)なのかmerge(挿入)などいろいろあります。
  mode: replace
```


2\. 作成したコンフィグを検証する。
　以下のコマンドにて、作成したコンフィグファイルを検証していきます。ただし、Embulkでの検証はコンフィグファイルの記述内容と移行元の読み込みまでで、 **移行先へのデータ投入検証はしません** ので注意してください。
```
$ embulk preview コンフィグファイル名 
```

3\. 実際に移行を実施する。
　検証にて問題がなければ、以下のコマンドで実際にデータの移行を行っていきます。
```
$ embulk run コンフィグファイル
```

エラー出力がなければ無事完了です。
移行先MySQKのデータを確認すると、以下の通りデータが格納されています。
```
+----+----------+-----------+
| id | user_id  | Event_ids |
+----+----------+-----------+
|  1 | 60523899 |     12-34 |
|  2 | 3f2dca9a |     12-34 |
|  3 | 3ed4938b |     12-34 |
|  4 | 96f320c7 |     12-34 |
|  5 | 1cf4d39e |     12-34 |
|  6 | 2477fb80 |     12-34 |
|  7 | b68aa077 |     12-34 |
+----+----------+-----------+
```

# 最後に
NoSQLからMySQLへ移行でしたが、Embulkを使用することで簡単にデータの転送ができました。
このEmbulk、調べるとBigQueryやmariaDB、Hadoopといったものにも各種プラグインを入れることでデータ転送ができるようです。(もちろんMySQL→MySQLといった同じ製品同士の転送もできます！\)

CYBIRD Advent Calendar 2023の12日目は、@cy-naullさんの記事です！ぜひ、そちらもご覧ください！