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回まで読むとだいたいつかめる。

第1回 使ってみようMongoDB | gihyo.jp
第1回目となる今回は、まずMongoDBの概要と特徴的な機能を解説し、どのようなケースで有効に使えるかを紹介します。

あと、こっちも。「MongoDBの薄い本」
http://www.cuspy.org/diary/2012-04-17/the-little-mongodb-book-ja.pdf

上の2つを読んだあと、オライリーの本を読んだら、飲み込みが早かったです。

JavaでMongoDBに登録する

サーバサイドがJavaなのは決まっていたので、MongoDBのドキュメントとにらめっこしながら。

What's New

補足的に、以下の記事を見るとやりやすいと思う。※サーバ接続の記述が古いままなので注意です。

JavaからMongoDBへのアクセス(接続、検索、insert、update、delete) – Qiita
Java MongoDB Driverを使ってJavaからMongoDBにアクセスする方法について、全くはじめての人向けメモ。 MongoDBには色々機能があるようですが、今回はJava MongoDB Driverを使った簡単なCRUDの500

スキーマ設計

「できるかぎりRDBを触らず、MongoDBだけで集計が済むようにする。」というのが、携わった案件の目標だったので、蓄積していくデータを考えることが重要でした。

以下の記事がスキーマ設計の仕方がすごくわかりやすかった。

今回は上の記事でいうスキーマ設計は「パターン2 明細埋め込み」でした。

MongoDBに入ったデータを集計する

クエリを考える

SQLが書けるなら、ここの記事がすごくわかりやすい。検索方法はだいたいこれみればわかる。

[Mongo] findメソッドのいろいろな使い方(MySQLと比較)
– YoheiM .NET
以前にフロントエンドエンジニアにオススメなデータベース、MongoDBに入門とフロントエンドエンジニアにもできるMongoDBを使ったログ分析のブログを書いたのち、MongoDBを引き続き使っていますが、findの使い方を調べることが多く、500

「MongoDB Aggregation Framework」で集計する

しかしながら、膨大なデータを集計し条件が複雑になるので、集計する上のクエリではなく「MongoDB Aggregation Framework」使うことになりました。

ただ、上のオライリーは Aggregation Framework をカバーしていないので、MongoDBのマニュアルを読むことが必要になってきます。ただし、英語オンリー。

Aggregation Operations – Database Manual – MongoDB Docs
Aggregation operations process multiple documents and return computed results.

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

MongoDBのAggregationについて基本的なこと – Qiita
最近RailsでMongoDBを使うことがあって、集計処理の部分でちょっと基本的な知識が不足気味な感じがしたので、公式ドキュメントを漁って理解を深めるなどしてみようかと。

MongoDB の Aggregation Framework でラクラク集計生活 (2.6 対応) – Qiita
どんなお話? MongoDB 2.6 で使い放題になった Aggregation Framework で集計してみたよ 簡単!(笑) MongoDBのデータを集計するなら、 Aggregation Framework がファーストチョイス 500

Moved Temporarily

読んだあとは、自分の集計したいクエリをひたすら実装するのみですな。

やっぱ、新しい技術を追うとなると英語を読むことが多くなりますね。ちょっとしたエラーなどの課題を解消するときにも英語が多くなりますし。発音できずとも、英語の意味を理解する力が必要になります。

私は英語だと毛嫌いせずに取り組める心構えは高校のときに身に付けたのは大きいですね。

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型と比較がどうがんばってもできない状況に……。

JSONIC POJOからJSONへの変換ルール ※抜粋
変換元(Java) 変換先(JSON)
Date, Calendar number (1970年からのミリ秒)

んで、対応策。

  • コレクションにドキュメントを追加するときに、「日付ミリ秒」のドキュメントを追加する。
  • matchパイプラインでは上で追加した「日付ミリ秒」で比較する。

「JSONがミリ秒に変換されるなら、MongoDBに持たせればいいじゃない!」
上司の発想の転換のうまさには頭が上がりませんね……!

まとめ

MongoDBを使った案件に携わって、ほんとうにNoSQLの集計機能の処理の早さにはびっくりしました。やり方をしっかりアプトプットされている先人の方々に感謝感謝です。

これからMongoDBを使う人の勉強の手助けになれば、うれしいです。