この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
菊池です。
先のブログで紹介しました通り、Database Migration Service(DMS)を使ってMongoDBを移行する際には、2つのマイグレーションモードがあります。
特に、テーブルモードでは、キーの追加が反映されないケースがあるなど、注意が必要です。今回は、DMSのCDCを使って、MongoDBからテーブルモードでS3に色々なデータパターンでの出力を検証してみました。
検証
SourceとしてEC2で動作するMongoDBのレプリカセット、TargetとしてS3を利用します。CDCを有効にしたタスクを実行したまま、MongoDBにデータを投入していきS3に出力されるファイルを確認します。
初期データのマイグレーション
まずはデータを1つMongoDBに挿入し、レプリケーションを実行します。
s0-rs0:PRIMARY> db.users.insert(
{
userid : 001,
name : "hoge1",
joined : ISODate("2017-04-01"),
likes : [ "tennis", "golf", "swimming" ]
}
);
s0-rs0:PRIMARY> db.users.find()
{ "_id" : ObjectId("59019806db68f3815096cf81"), "userid" : 1, "name" : "hoge1", "joined" : ISODate("2017-04-01T00:00:00Z"), "likes" : [ "tennis", "golf", "swimming" ] }
S3に出力されたファイルLOAD00000001.csv
は以下のようになります。
$ cat LOAD00000001.csv
"59019806db68f3815096cf81",+1.0000000000000000e+00,"hoge1",2017-04-01 00:00:00,"[ "tennis", "golf", "swimming" ]"
配列にしたlike
は1つの文字列のカラムとして出力されています。
未定義のキーの追加
ここからがCDCでの出力の確認です。マイグレーション開始時のデータには存在しなかったキーage
を追加したデータを挿入します。
s0-rs0:PRIMARY> db.users.insert(
... {
... userid : 002,
... name : "hoge2",
... joined : ISODate("2017-04-01"),
... age : 22
... }
... );
CDCでS3に追加したファイルを確認します。
$ cat 20170427-0708476670.csv
"590198c3db68f3815096cf82",+2.0000000000000000e+00,"hoge2",2017-04-01 00:00:00,
やはり、追加されたキーのデータは反映できていません。
配列の項目に文字列
次に、初期データには配列が入っていたlike
に文字列のデータを挿入してみます。
s0-rs0:PRIMARY> db.users.insert(
... {
... userid : 003,
... name : "hoge3",
... likes : "golf"
... }
... );
出力結果です。
$ cat 20170427-0709486721.csv
"590198fbdb68f3815096cf83",+3.0000000000000000e+00,"hoge3",,
CDCのキャプチャーデータには反映されていません。配列の項目は配列のままである必要がありそうです。
異なるデータ型
定義済みのキーに対し、異なるデータ型の値を入れた場合です。userid
に文字列のデータを挿入します。
s0-rs0:PRIMARY> db.users.insert(
... {
... userid : "004",
... name : "hoge4"
... }
... );
出力です。
$ cat 20170427-0711000591.csv
"59019946db68f3815096cf84",,"hoge4",,
こちらも、userid
は出力できないようです。
ネストしたJSONを追加
定義済みのキーに対し、ネストするデータを追加してみます。
s0-rs0:PRIMARY> db.users.insert(
... {
... userid : 005,
... name : {
... first : "hoge5-1",
... last : "hoge5-2"
... }
... }
... );
出力結果の確認です。
$ cat 20170427-0712121807.csv
"5901998fdb68f3815096cf85",+5.0000000000000000e+00,,,
キーが同じでも、ネストさせると追加は反映できないようです。
配列で追加
続いて、同様に定義済みのキーに対し、配列でデータを入れてみます。name
に配列のデータを挿入します。
s0-rs0:PRIMARY> db.users.insert(
... {
... userid : 006,
... name: [ "hoge6-1" , "hoge6-2" ]
... }
... );
出力結果です。
$ cat 20170427-0713186461.csv
"590199d3db68f3815096cf86",+6.0000000000000000e+00,,,
これはいけるかとも思いましたが、やはり、CDCにの出力には反映されません。
異なる要素数の配列
では、もともと配列であったlike
に、要素数を変えたデータの場合はどうでしょうか。
s0-rs0:PRIMARY> db.users.insert(
... {
... userid : 008,
... name : "hoge8",
... likes : ["tennis"]
... }
... );
結果です。
$ cat 20170427-0714238535.csv
"59019a11db68f3815096cf87",+8.0000000000000000e+00,"hoge8",,"[ "tennis" ]"
さすがにこれはちゃんと反映できました。
配列にJSONをネスト
では、配列の項目に、JSONでデータを入れてみます。
s0-rs0:PRIMARY> db.users.insert(
... {
... userid : 007,
... name : "hoge7",
... likes : [ {
... first : "tennis",
... second : "golf"
... } ]
... }
... );
結果です。
$ cat 20170427-0716181931.csv
"59019a82db68f3815096cf88",+7.0000000000000000e+00,"hoge7",,"[ { "first" : "tennis", "second" : "golf" } ]"
なんと、このパターンは反映されました!配列の中身は丸ごと文字列扱いされるのか、JSONを入れても出力されています。
再度初期レプリケーションを実行
ここまででMongoDBのデータは以下のようになっています。
s0-rs0:PRIMARY> db.users.find()
{ "_id" : ObjectId("59019806db68f3815096cf81"), "userid" : 1, "name" : "hoge1", "joined" : ISODate("2017-04-01T00:00:00Z"), "likes" : [ "tennis", "golf", "swimming" ] }
{ "_id" : ObjectId("590198c3db68f3815096cf82"), "userid" : 2, "name" : "hoge2", "joined" : ISODate("2017-04-01T00:00:00Z"), "age" : 22 }
{ "_id" : ObjectId("590198fbdb68f3815096cf83"), "userid" : 3, "name" : "hoge3", "likes" : "golf" }
{ "_id" : ObjectId("59019946db68f3815096cf84"), "userid" : "004", "name" : "hoge4" }
{ "_id" : ObjectId("5901998fdb68f3815096cf85"), "userid" : 5, "name" : { "first" : "hoge5-1", "last" : "hoge5-2" } }
{ "_id" : ObjectId("590199d3db68f3815096cf86"), "userid" : 6, "name" : [ "hoge6-1", "hoge6-2" ] }
{ "_id" : ObjectId("59019a11db68f3815096cf87"), "userid" : 8, "name" : "hoge8", "likes" : [ "tennis" ] }
{ "_id" : ObjectId("59019a82db68f3815096cf88"), "userid" : 7, "name" : "hoge7", "likes" : [ { "first" : "tennis", "second" : "golf" } ] }
一度レプリケーションを停止し、再度初期レプリケーションを実行して出力してみました。
$ cat LOAD00000001.csv
"59019806db68f3815096cf81",+1.0000000000000000e+00,"hoge1",2017-04-01 00:00:00,"[ "tennis", "golf", "swimming" ]",,,,,
"590198c3db68f3815096cf82",+2.0000000000000000e+00,"hoge2",2017-04-01 00:00:00,,+2.2000000000000000e+01,,,,
"590198fbdb68f3815096cf83",+3.0000000000000000e+00,"hoge3",,,,"golf",,,
"59019946db68f3815096cf84",,"hoge4",,,,,,,
"5901998fdb68f3815096cf85",+5.0000000000000000e+00,,,,,,"hoge5-1","hoge5-2",
"590199d3db68f3815096cf86",+6.0000000000000000e+00,,,,,,,,"[ "hoge6-1", "hoge6-2" ]"
"59019a11db68f3815096cf87",+8.0000000000000000e+00,"hoge8",,"[ "tennis" ]",,,,,
"59019a82db68f3815096cf88",+7.0000000000000000e+00,"hoge7",,"[ { "first" : "tennis", "second" : "golf" } ]",,,,,
"59019cf3db68f3815096cf89",+2.0000000000000000e+00,"hoge2",2017-04-01 00:00:00,,+2.2000000000000000e+01,,,,
これを見ると、出力できてなかった項目は、1行目(初期レプリケーションされたデータ)に定義されたカラムとは別のカラムとして認識されているのがわかりますね。
まとめ
MongoDBをテーブルモードでレプリケーションする際に、CDCでキャプチャ可能なデータ変更について調べてみました。MongoDBは柔軟で自由なデータ構造が大きな特徴ですが、DMSで継続的にレプリケーションするためにはある程度の制限を持って運用する必要があります。
DMSを使う場合に限らず、自由にデータを入れてしまうと後々のデータ連携や活用に支障がでる場合もあります。MongoDBではDB側でデータ構造を縛ることが基本的にできませんので、後になって困らないよう運用していきましょう。