【MongoDB】集計パイプラインの$groupを使って日付ごとにデータをグループ化する方法
MongoDBで日付ごとにドキュメントをグループ化したい場合は、aggregate()メソッド内で$group演算子を使用します。本記事では、サンプルコードを交えながら、コレクションの作成から日付単位でのグループ化までの一連の手順をわかりやすく解説します。
1. サンプルコレクションの作成
まず、日付情報を含むドキュメントを格納するコレクションを用意しましょう。以下の例では、db.demo657というコレクションに対して、id、Name、DueDate(ISODate形式)の各フィールドを持つドキュメントを、insertOne()メソッドで3件挿入しています。
> db.demo657.insertOne({
... id: 1,
... Name: "Chris",
... DueDate: new ISODate("2020-04-22")
... }
... );
{
"acknowledged" : true,
"insertedId" : ObjectId("5ea064b44deddd72997713d6")
}
> db.demo657.insertOne(
... {
... id: 1,
... Name: "John",
... DueDate: new ISODate("2020-04-22")
... }
...);
{
"acknowledged" : true,
"insertedId" : ObjectId("5ea064b44deddd72997713d7")
}
> db.demo657.insertOne(
... {
... id: 1,
... Name: "Chris",
... DueDate: new ISODate("2020-04-22")
... }
...);
{
"acknowledged" : true,
"insertedId" : ObjectId("5ea064b44deddd72997713d8")
}ここでのポイントは、DueDateフィールドにISODate型で日付を保存している点です。文字列として日付を保存してしまうと、後の集計処理で日付演算子($year、$monthなど)が使えなくなるため注意が必要です。
2. 挿入したドキュメントの確認
find()メソッドを使うと、コレクション内のすべてのドキュメントを確認できます。
> db.demo657.find();
実行すると、以下のような結果が出力されます。
{ "_id" : ObjectId("5ea064b44deddd72997713d6"), "id" : 1, "Name" : "Chris", "DueDate" : ISODate("2020-04-22T00:00:00Z") }
{ "_id" : ObjectId("5ea064b44deddd72997713d7"), "id" : 1, "Name" : "John", "DueDate" : ISODate("2020-04-22T00:00:00Z") }
{ "_id" : ObjectId("5ea064b44deddd72997713d8"), "id" : 1, "Name" : "Chris", "DueDate" : ISODate("2020-04-22T00:00:00Z") }3件すべてのドキュメントが、2020年4月22日の期日(DueDate)を持っていることが確認できました。
3. 日付でグループ化する集計クエリ
それでは、本題である「日付によるグループ化」のクエリを見ていきましょう。以下のように、aggregate()パイプラインの中で$match → $project → $groupの3つのステージを順番に組み合わせます。
> db.demo657.aggregate([
... {$match: {id:1, DueDate: {$gte:new ISODate('2020-04-21'), $lt:new ISODate("2020-04-23")}}},
... {$project:
... {day: {'$dayOfMonth': '$DueDate'},month: {'$month':'$DueDate'},year: {'$year':'$DueDate'},Name:"$Name" }
},
... {$group: {
... _id: {day:'$day',month:'$month',year:'$year'},
... ListOfNames: {$push:{Name:'$Name'}}
... }}
... ])実行結果は以下の通りです。
{ "_id" : { "day" : 22, "month" : 4, "year" : 2020 }, "ListOfNames" : [ { "Name" : "Chris" }, { "Name" : "John" }, { "Name" : "Chris" } ] }4. クエリの仕組みを解説
それぞれのステージがどのような役割を果たしているのか、順を追って説明します。
$match:対象ドキュメントの絞り込み
最初のステージでは、idが1であり、かつDueDateが「2020年4月21日以上・2020年4月23日未満」の範囲にあるドキュメントだけを抽出しています。$gte(以上)と$lt(未満)を組み合わせることで、特定の日付範囲を正確に指定できるのがポイントです。
$project:日付の分解と必要フィールドの選択
次に$projectステージで、DueDateから日付演算子を使って値を取り出しています。
$dayOfMonth: 日(22)$month: 月(4)$year: 年(2020)
あわせて、グループ化後に表示したいNameフィールドも残しています。
$group:年月日をキーとしてグループ化
最後に$groupステージで、年・月・日の組み合わせを_idとして設定し、同一の日付に属するドキュメントを1つにまとめます。$push演算子を使うことで、同じグループ内のNameの値がListOfNamesという配列に蓄積されていきます。
5. 結果の読み方と実務上のポイント
出力結果を見ると、「2020年4月22日」というキーの下に、Chris・John・Chrisという3人の名前が配列としてまとめられていることがわかります。これにより、「ある日付に紐づくデータを一覧したい」「日別の集計を行いたい」といった要件に柔軟に対応できます。
なお、実運用では以下の点にも留意するとよいでしょう。
- $matchをパイプラインの先頭に配置することで、処理対象のドキュメント数を早い段階で減らせます。インデックスが張られたフィールドで絞り込めば、パフォーマンスはさらに向上します。
- タイムゾーンを考慮する必要がある場合は、
$yearや$monthなどの日付演算子にtimezoneオプションを指定できます。 - 日別・月別などの統計を頻繁に取得する場合は、あらかじめ
DueDateにインデックスを作成しておくことをおすすめします。
このように、MongoDBの集計フレームワーク(Aggregation Pipeline)を使えば、日付単位のグループ化もシンプルかつ効率的に実現できます。ぜひ自身のプロジェクトでも応用してみてください。
-
MongoDBでコレクションの名前を変更する方法(renameCollectionの使い方)
MongoDBで既存のコレクションの名前を変更したい場合、renameCollection()メソッドを使用します。この記事では、実際にコレクションを作成し、その名前を変更するまでの手順を順番に解説します。1. ドキュメントを含むコレクションを作成するまず、insertOne()メソッドを使ってサンプルドキュメントを挿入し、コレクション「demo690」を作成します。> db.demo690.insertOne({_id:101,Name:Sam}); { acknowledged : true, insertedId : 101 } > db.demo690.insertOne(
-
MongoDBコレクションにインデックスを作成する方法
MongoDBコレクションにインデックスを作成する方法MongoDBでインデックスを作成するには、createIndex()メソッドを使用します。インデックスを適切に設定することで、クエリの検索速度を大幅に向上させることができます。まず、ドキュメントを含むコレクションに対してインデックスを作成してみましょう。以下の例では、details.idフィールドに対して昇順(1)のインデックスを作成しています。> db.demo702.createIndex({details.id:1});{ createdCollectionAutomatically : tr