MongoDBのgroup(aggregate)の使い方(検索結果を集計する)

集計
MongoDBで検索結果を集計するgroup(aggregate)の使い方を解説します。

公式ページ(aggregate)が難しかったので共有します。

 

group化した列をカウントする

サンプルデータ

> db.blogtest.find();
{ "_id" : ObjectId("5c6…"), "title" : "Node.jsでWebサーバ構築", "access_number" : 1 }
{ "_id" : ObjectId("5c6…"), "title" : "Node.jsでWebサーバ構築", "access_number" : 3 }
{ "_id" : ObjectId("5c6…"), "title" : "MongoDBサンプルコード", "access_number" : 2 }
{ "_id" : ObjectId("5c6…"), "title" : "Node.jsでWebサーバ構築", "access_number" : 1 }
{ "_id" : ObjectId("5c6…"), "title" : "Node.jsでWebサーバ構築", "access_number" : 3 }
{ "_id" : ObjectId("5c6…"), "title" : "MongoDBサンプルコード", "access_number" : 2 }
{ "_id" : ObjectId("5c6…"), "title" : "MongoDBサンプルコード", "access_number" : 0 }
{ "_id" : ObjectId("5c6…"), "title" : "MongoDB構築", "access_number" : 5 }

db.collection.aggregate()を使用します。
SQLで言うgroup byに相当します。
引数に$group: {_id:”$(列名)”}のような使い方をします。

#{$sum: 1}でgroup化した列をカウントできます。

> db.blogtest.aggregate(
{ $group   : { _id  : "$title",
 "average"   : { $avg : "$access_number" }, // _idでgroup化した"title"ごとのデータの平均
 "sum" : { $sum : "$access_number" }, // _idでgroup化した"title"ごとのデータの合計
 "postNum"   : { $sum : 1 } // _idでgroup化したデータの合計(sum:1)
}},
 {$sort: {"average":-1}} // averageで降順にソート
);


// 検索結果 { "_id" : "MongoDB構築", "average" : 5, "sum" : 5, "postNum" : 1 } { "_id" : "MongoDBサンプルコード", "average" : 1.3333333333333333, "sum" : 4, "postNum" : 3 } { "_id" : "Node.jsでWebサーバ構築", "average" : 1.25, "sum" : 5, "postNum" : 4 }

複数の項目でgroup化した列を集計する

同じくdb.collection.aggregate()を使用します。
引数に$group: {_id:”$(列名1)”,”$(列名2)”}のような使い方をします。

サンプルデータ&コード

// DBの中身を確認
> db.blogtest.find() { "_id" : "title" : "Node.jsでWebサーバ構築", "category" : "Node.js", "access_number" : 1 } { "_id" : "title" : "Node.jsでWebサーバ構築", "category" : "Node.js", "access_number" : 3 } { "_id" : "title" : "Node.jsでWebサーバ構築", "category" : "Web", "access_number" : 0 } { "_id" : "title" : "Node.jsでWebサーバ構築", "category" : "Web", "access_number" : 1 } { "_id" : "title" : "MongoDBサンプルコード", "category" : "MongoDB", "access_number" : 1 } { "_id" : "title" : "MongoDB構築", "category" : "MongoDB", "access_number" : 5 } { "_id" : "title" : "MongoDBサンプルコード", "category" : "MongoDB", "access_number" : 2 } { "_id" : "title" : "MongoDBサンプルコード", "category" : "MongoDB", "access_number" : 1 }

// Aggregateコマンドを実行 > db.blogtest.aggregate( ... { $group : ... { ... _id : {"title": "$title","category": "$category"}, ... "max": {$max : "$access_number" } ... } ... });

// 実行結果 { "_id" : { "title" : "MongoDB構築", "category" : "MongoDB" }, "max" : 5 } { "_id" : { "title" : "MongoDBサンプルコード", "category" : "MongoDB" }, "max" : 2 } { "_id" : { "title" : "Node.jsでWebサーバ構築", "category" : "Web" }, "max" : 1 } { "_id" : { "title" : "Node.jsでWebサーバ構築", "category" : "Node.js" }, "max" : 3 } >

group化した列を集計した結果をさらにgroup化する

group化して抽出した検索結果(合計)をさらにgroup化したい場合のサンプルです。

例えば、「カテゴリごとの合計」を取得して、その「平均」を取得するなどの場合です。

引数に$group: {_id:”$(列名1)”,”$(列名2)”},$group: {_id:”$(列名1)”},のような使い方をすることで検索結果をgroup化できます。

サンプルデータ&コード

// DBの中身を確認
> db.blogtest.find(); { "_id" : "date" : "2019/1/10", "title" : "Node.jsでWebサーバ構築", "category" : "Node.js", "access_number" : 1 } { "_id" : "date" : "2019/1/11", "title" : "Node.jsでWebサーバ構築", "category" : "Node.js", "access_number" : 3 } { "_id" : "date" : "2019/2/12", "title" : "Node.jsでWebサーバ構築", "category" : "Web", "access_number" : 0 } { "_id" : "date" : "2019/1/13", "title" : "Node.jsでWebサーバ構築", "category" : "Web", "access_number" : 1 } { "_id" : "date" : "2019/2/10", "title" : "MongoDBサンプルコード", "category" : "MongoDB", "access_number" : 1 } { "_id" : "date" : "2019/2/11", "title" : "MongoDB構築", "category" : "MongoDB", "access_number" : 5 } { "_id" : "date" : "2019/1/12", "title" : "MongoDBサンプルコード", "category" : "MongoDB", "access_number" : 2 } { "_id" : "date" : "2019/1/13", "title" : "MongoDBサンプルコード", "category" : "MongoDB", "access_number" : 1 }
// Aggregateを実行 > db.blogtest.aggregate( ... { $group : ... { ... _id : {"postMonth":{$substr:["$date",5,1]},"title": "$title","category": "$category"}, ... "max": {$max : "$access_number" } ... } ... }, ... { $group : ... { ... _id : {"postMonth": "$_id.postMonth","category": "$_id.category"}, ... "average" : { $avg : "$max"} ... } ... } ... );

// 検索結果 { "_id" : { "postMonth" : "1", "category" : "Node.js" }, "average" : 3 } { "_id" : { "postMonth" : "1", "category" : "Web" }, "average" : 1 } { "_id" : { "postMonth" : "2", "category" : "MongoDB" }, "average" : 3 } { "_id" : { "postMonth" : "2", "category" : "Web" }, "average" : 0 } { "_id" : { "postMonth" : "1", "category" : "MongoDB" }, "average" : 2 }

Queryでエラーが発生した時は

E QUERY    [js] SyntaxError: invalid property id @(shell):7:4

@(shell):7:4に注目しましょう。
7列目の左から4つ目に原因があります。

ブログ用サンプル作成ではまってしまいました。invalid property idといいつつ、括弧が足りてなかったとは。。最初にちゃんと場所特定すればよかった。。

MongoDBの使い方まとめに戻る。

自作アプリケーションを作るならさくらのVPS が手軽で使いやすいです。MongoDBは軽いので最低料金プランのVPSでも運用できます。【初めてでも簡単!】VPSの比較ランキングでも紹介しています。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

CAPTCHA


ABOUT US

ケネ
はじめまして、ケネです。

Node.jsの技術情報を書いています。

一人でも多くの方と「自分でもできた」感覚を共有したいので、なるべくわかりやすく、実体験ベースでのブログを心がけています。
技術で自分の世界を広げましょう。

不明点や質問があればお気軽にコメントください。