MongoDB において 日付ごとにレコード数や総数、最小、最大、平均などを集計する方法をまとめます。
前提データ
以下のコードを利用して前提データを投入し、投入された db.figures
に対して集計を行うサンプルを見ていきます。
キーとなる日付 datetime
は Date型
で入れてあるものを前提に集計方法を見ていきます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | var MongoClient = require( "mongodb" ).MongoClient; var moment = require( "moment" ); MongoClient.connect(CONNECTION_URL).then((db) => { var bulk = db.collection( "figures" ).initializeOrderedBulkOp(); bulk.insert({ datetime: moment( "2017/10/29" , "YYYY/M/D" ).toDate(), item: "ABC" , price: 120 }); bulk.insert({ datetime: moment( "2017/10/29" , "YYYY/M/D" ).toDate(), item: "ABC" , price: 120 }); bulk.insert({ datetime: moment( "2017/10/29" , "YYYY/M/D" ).toDate(), item: "BCD" , price: 150 }); bulk.insert({ datetime: moment( "2017/10/30" , "YYYY/M/D" ).toDate(), item: "ABC" , price: 120 }); bulk.insert({ datetime: moment( "2017/10/30" , "YYYY/M/D" ).toDate(), item: "BCD" , price: 150 }); bulk.insert({ datetime: moment( "2017/11/1" , "YYYY/M/D" ).toDate(), item: "BCD" , price: 150 }); bulk.insert({ datetime: moment( "2017/11/2" , "YYYY/M/D" ).toDate(), item: "ABC" , price: 120 }); bulk.insert({ datetime: moment( "2017/11/2" , "YYYY/M/D" ).toDate(), item: "BCD" , price: 150 }); bulk.insert({ datetime: moment( "2017/11/2" , "YYYY/M/D" ).toDate(), item: "CDE" , price: 180 }); bulk.execute().then((result) => { db.close(); }); }); |
集計コード
集計には db.collection.aggregate()
の $group
コマンドを利用します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | var MongoClient = require( "mongodb" ).MongoClient; var moment = require( "moment" ); MongoClient.connect(CONNECTION_URL).then((db) => { db.collection( "figures" ).aggregate([ { $group: { _id: { yyyy: { $year: "$datetime" }, mm: { $month: "$datetime" }, dd: { $dayOfMonth: "$datetime" } }, datetime: { $first: "$datetime" }, total: { $sum: "$price" }, min: { $min: "$price" }, max: { $max: "$price" }, average: { $avg: "$price" }, count: { $sum: 1 } } }, { $project: { _id: 0, datetime: 1, total: 1, min: 1, max: 1, average: 1, count: 1 } }, { $sort: { datetime: 1 } } ], (err, results) => { console.log(JSON.stringify(results)); }); }); |
日付ごとに集計する場合、 _id
に日時を分解して入れるのがポイントになります。
グループ化する際のキーとなる日付に対して、Date型
から年月日を取り出すオペレーターは $year
, $month
, $dayOfMonth
になります。
また、集計に利用できるコマンドとしては $sum
(合計値計算), $min
(最小値), $max
(最大値), $avg
(平均値) などがあります。
その他サブコマンドについては Group Accumulator Operators - MongoDB を参照してください。
aggregate()
パイプラインの2番目の $project
では 返却するドキュメントで不要な _id
を削除しています。
パイプライン3番目の $sort
では日付の昇順に並び替えをしています。
何も指定していないと順番は適当な順になってしまいます。
集計結果
上記「集計コード」を実行した結果は以下のようになります。
1 2 3 4 5 6 | [ { "datetime" : "2017-10-28T15:00:00.000Z" , "total" :390, "min" :120, "max" :150, "average" :130, "count" :3}, { "datetime" : "2017-10-29T15:00:00.000Z" , "total" :270, "min" :120, "max" :150, "average" :135, "count" :2}, { "datetime" : "2017-10-31T15:00:00.000Z" , "total" :150, "min" :150, "max" :150, "average" :150, "count" :1}, { "datetime" : "2017-11-01T15:00:00.000Z" , "total" :450, "min" :120, "max" :180, "average" :150, "count" :3} ] |
必要な集計結果が得られていることが確認できるかと思います。
datetime
に入っている日時は要注意です。
データ投入時は「日本時間(+09:00)」で投入していますが、取り出す際は「グリニッジ標準時間(+00:00)」で取り出しているので、日時がずれたように見えます。
この時差は moment.js
などを利用して日本時間に直して利用したほうがわかりやすくなると思います。
今回の記事は参考になったでしょうか。 MongoDB の aggregation はいろいろとできるようなので、今後も面白そうなネタがあれば取り上げていきたいと思います!!
最後に… このブログに興味を持っていただけた方は、 ぜひ 「Facebookページ に いいね!」または 「Twitter の フォロー」 お願いします!!