MongoDB

45歳以上はMongoDBを使ったシステムが使えなくなる件

More than 3 years have passed since last update.

MongoDBを使うシステムが、最近多いと思います。

2.6系(安定版)の最新2.6.7ですが、Date型のインポート処理にバグがありそうです。

「1970/01/01」以前の Date型 を mongoexport すると、負の "$numberLong" として出力されるのですが、それを mongoimport すると、それ以降のフィールドが欠落してしまうのです。

例えば、ユーザマスタに「誕生日」フィールドがあると、45歳以上の人は「1970/01/01」以前の値が入っているわけで、マスタデータを移行したりでもすると、その人のフィールドがガッツリ無くなってしまいます。でも若手は大丈夫だから「どうせ部長の使い方がおかしいんでしょwww」といういつもの「偉い人に限って障害が発生する」パターンが展開されます。

大急ぎで調べた所、以下が判明しました。

2.6形式

"1965-11-17T00:00:00Z" → "$date : { $numberLong": "-130118400000" }

"2014-04-24T00:00:00Z" → "$date": "2014-04-24T09:00:00.000+0900"

2.4形式

"1965-11-17T00:00:00Z" → "$date : -130118400000

"2014-04-24T00:00:00Z" → "$date": 1398297600000

2.4系では "$numberLong" を使わないフォーマットです。また、2.6系は2.4系のエクスポートファイルであれば、正常に読み込むことができるようです。

そこで、2.6系で出力したjsonを安全に読めるように変換するコンバータを作成しました。(node.js版)

(エクスポートしたjsonを標準入力で受け取り、標準出力に吐き出す)

var fs = require('fs'),

readline = require('readline'),
rs = process.stdin,
rl = readline.createInterface({'input': rs, 'output': {}});

var re1 = new RegExp(/({ "[$]date" : { "[$]numberLong" : "-[0-9]+" } })/g);
var re2 = new RegExp(/({ "[$]numberLong" : "(-[0-9]+)" })/);
rl.on('line', function (line) {
line = line.replace(re1, function (term) {
term = term.replace(re2, function (a, b, num) {
return num;
});
return term;
});
console.log(line);
});
rl.resume();

使い方

$ node convert.js < エクスポート.json > 変換後エクスポート.json

これで、上司に怒られずに済みますね。