the little book mongodbは無料で読めるMongoDBの本です。
MongoDBの薄い本として有志による日本語訳も公開されています。
先日、英語の勉強も兼ねて日本語訳で補完しながら原文を読んでいたところ、いくつか異なる部分を見つけました。
中でも、Chapter 6 - Aggregating Dataの部分が日本語訳ではMap Reduceとなっていて、結構内容が異なります。
というのも、原文のほうが2014年5月にガッツリ変わっているようです。
MongoDBのRelease Noteを追ってみると確かにそのあたり(2.2~2.4らへん)がAggregationFrameworkが導入されたようなのでそれを受けての改稿かと思われます。
今回は、そのAggregating Dataの部分をざっくりと訳してざっくり説明します。
使うデータなどは原文を参照。
ユニコーンのデータらしい。My Little Ponyとかその辺かと思ったら違った。
vampiresというフィールドも謎なんだけど、何か元ネタとかあるのかなあ。
Aggregating Data
集約パイプライン
集約パイプラインはコレクション内のドキュメントに対して、(UNIXのパイプのように)変換して組み合わせることができます。
今まで使ってきたcount()は単純な数なら数えられましたが、男性、女性の各人数を知りたいときには以下のようにします。
db.unicorns.aggregate([
{$group:{_id:'$gender',total: {$sum:1}}}
])
{ "_id" : "f", "total" : 5 }
{ "_id" : "m", "total" : 7 }
$group
はSQLでのGROUP BYのように_id
フィールドによってグループ化を行います。
フィールドの値を参照するため、gender
ではなく、$gender
になります。
そのほかの演算子としては、$match
があります。これは、集約されるドキュメントを制限します(find
の条件部分のようなもの)。
db.unicorns.aggregate([
{$match: {weight:{$lt:600}}},
{$group: {_id:'$gender', total:{$sum:1}, avgVamp:{$avg:'$vampires'}}},
{$sort:{avgVamp:-1}}
])
{ "_id" : "f", "total" : 3, "avgVamp" : 61.5 }
{ "_id" : "m", "total" : 2, "avgVamp" : 50.5 }
$sort
を使って集約結果をソートすることができる。$limit
や$skip
も用意されています。
また、$group
の中では$avg
を使って平均を求めることもできます。
配列の内部に格納されている値を集約したい場合は、一度$unwind
演算子を使ってフラットにする必要があります。
db.unicorns.aggregate([
{$unwind:'$loves'},
{$group: {_id:'$loves', total:{$sum:1}, unicorns:{$addToSet:'$name'}}},
{$sort:{total:-1}},
{$limit:3}
])
{ "_id" : "apple", "total" : 5, "unicorns" : [ "Solnara", "Raleigh", "Leia", "Pilot", "Roooooodles" ] }
{ "_id" : "carrot", "total" : 4, "unicorns" : [ "Solnara", "Nimue", "Aurora", "Horny" ] }
{ "_id" : "grape", "total" : 4, "unicorns" : [ "Kenny", "Dunx", "Nimue", "Aurora" ] }
多くのユニコーンが好きな食べ物のリストを、$limit
を使うことで上位N番目を得ることができます。
そのほかにも、特定のフィールドの値を利用して新しいフィールドの作成を行うことが$project
という強力な演算子も用意されています。
バージョン2.6からは集約は(1章の)カーソルを返したり、$out
演算子により別のコレクションに結果を書き込むことができるようになり、より強力なものとなっています。
そのほかの演算子や例についてはMongoDBのマニュアルを参照してください。