NoSQLのひとつであるMongoDBを仕事で使いまして、基本設計から実装・テスト・実際にリリースまでこぎつけしました。
新しい技術はGoogle先生から先行者の記事たちのありがたみを感じる日々。感謝もこめて、参考になった記事、つまづいたところとかをまとめました。
どんな業務でMogoDBを使ったの?
スマホアプリの実績集計のデータ蓄積にMongoDBを使用しました。スマホアプリの履歴情報を別のWebシステムで蓄積したデータを集計して、グラフ表示します。
サーバサイドのシステム構成はこんな感じ。
- Java 1.8
- Spring Framework 4.3.4
- MyBatis 3.3.0
- JSONIC 1.3.10
- MySQL5.7
- MongoDB 3.4
マスタや基本的な業務はMySQLで実績のデータだけMongoDBを利用しています。
そもそもMongoDBについて知りたい!
MongoDBとは、ドキュメント指向データベースです。スキーマを定義しなくても使用できるスキーマレスである
複雑な検索条件でデータを取得することが可能になります。
かなり暴言的な言い方だけど、「JSON形式に似たオブジェクトデータを、入れ子になっていてもそのままDBに入れて、検索したり集計するとすっごく早いよ!」ていうDBです。
下のシリーズはMongoDBとはなんぞや、がすごくわかりやすかったですね。第5回まで読むとだいたいつかめる。

あと、こっちも。「MongoDBの薄い本」
http://www.cuspy.org/diary/2012-04-17/the-little-mongodb-book-ja.pdf
上の2つを読んだあと、オライリーの本を読んだら、飲み込みが早かったです。
JavaでMongoDBに登録する
サーバサイドがJavaなのは決まっていたので、MongoDBのドキュメントとにらめっこしながら。
補足的に、以下の記事を見るとやりやすいと思う。※サーバ接続の記述が古いままなので注意です。

スキーマ設計
「できるかぎりRDBを触らず、MongoDBだけで集計が済むようにする。」というのが、携わった案件の目標だったので、蓄積していくデータを考えることが重要でした。
以下の記事がスキーマ設計の仕方がすごくわかりやすかった。
今回は上の記事でいうスキーマ設計は「パターン2 明細埋め込み」でした。
MongoDBに入ったデータを集計する
クエリを考える
SQLが書けるなら、ここの記事がすごくわかりやすい。検索方法はだいたいこれみればわかる。

– YoheiM .NET
「MongoDB Aggregation Framework」で集計する
しかしながら、膨大なデータを集計し条件が複雑になるので、集計する上のクエリではなく「MongoDB Aggregation Framework」使うことになりました。
ただ、上のオライリーは Aggregation Framework をカバーしていないので、MongoDBのマニュアルを読むことが必要になってきます。ただし、英語オンリー。

使えるようになるまでかなり苦戦した。以下の記事を見ると、つかみばっちり。


読んだあとは、自分の集計したいクエリをひたすら実装するのみですな。
やっぱ、新しい技術を追うとなると英語を読むことが多くなりますね。ちょっとしたエラーなどの課題を解消するときにも英語が多くなりますし。発音できずとも、英語の意味を理解する力が必要になります。
私は英語だと毛嫌いせずに取り組める心構えは高校のときに身に付けたのは大きいですね。
Javaで「MongoDB Aggregation Framework」を使う
このへんもあまり記事になく。
Aggregation PipelineをMapに格納
→JSONに変換
→BSONに変換
→クエリ実行
上の処理をひたすらすることに落ち着きました。
JSON変換してからBSONするのは、文字エスケープ処理するためですね。
Aggregation Pipelineを作るには、Javaはひたすら変数作って格納することになるので、ソースがすっごく長ったらしくなってしまいます。これはどうしても避けられないですね。
今後、カンタンに組めるような仕組みがドライバー内で増えないかなぁ。(かゆいところに手が届くフレームワークが今後出てきそうですね。)
日付の処理
mongodbのISODateはtimezoneに対応してません。タイムゾーンが入ったのDate型を入れても、標準時間でドキュメントを登録されます。
なので、以下の記事のように「MongoDB Aggregation Framework」を使ってタイムゾーンを修正するなど、ひと手間が必要です。
JSON変換をする際、jsonicを使用しています。
この変換させる処理で、上のMongoDBのISODate型と比較がどうがんばってもできない状況に……。
| 変換元(Java) | 変換先(JSON) |
|---|---|
| Date, Calendar | number (1970年からのミリ秒) |
んで、対応策。
- コレクションにドキュメントを追加するときに、「日付ミリ秒」のドキュメントを追加する。
- matchパイプラインでは上で追加した「日付ミリ秒」で比較する。
「JSONがミリ秒に変換されるなら、MongoDBに持たせればいいじゃない!」
上司の発想の転換のうまさには頭が上がりませんね……!
まとめ
MongoDBを使った案件に携わって、ほんとうにNoSQLの集計機能の処理の早さにはびっくりしました。やり方をしっかりアプトプットされている先人の方々に感謝感謝です。
これからMongoDBを使う人の勉強の手助けになれば、うれしいです。