この章では、MongoDBの統計解析について詳しく説明します。主に集計パイプラインを使用して行われ、SQLの「group by」ステートメントに類似しています。MongoDBシェルでは、統計解析はdb.collection.aggregate()関数を使用して実装されます。

前提チュートリアル

MongoDB Aggregation Pipeline

一般的な手順

  • $matchを使用して対象データをフィルタリングする
  • $groupを使用してデータをグループ化し、計算する
  • 結果をソートするために$sortを使用する(オプション)

テストデータ

ordersコレクション内のデータは以下のようになります

{ _id: 1, cust_id: "abc1", ord_date: ISODate("2012-11-02T17:04:11.102Z"), status: "A", amount: 50 }
{ _id: 2, cust_id: "xyz1", ord_date: ISODate("2013-10-01T17:04:11.102Z"), status: "A", amount: 100 }
{ _id: 3, cust_id: "xyz1", ord_date: ISODate("2013-10-12T17:04:11.102Z"), status: "D", amount: 25 }
{ _id: 4, cust_id: "xyz1", ord_date: ISODate("2013-10-11T17:04:11.102Z"), status: "D", amount: 125 }
{ _id: 5, cust_id: "abc1", ord_date: ISODate("2013-11-12T17:04:11.102Z"), status: "A", amount: 25 }

aggregate 関数

db.collection.aggregate(pipeline) 説明:

  • pipelineは配列パラメータを取り、各要素が処理段階を表します。

db.orders.aggregate([
                     { $match: { status: "A" } },  // 最初の段階
                     { $group: { _id: "$cust_id", total: { $sum: "$amount" } } },   // 2番目の段階
                     { $sort: { total: -1 } }  // 3番目の段階
                   ])

同等なSQL

select sum(amount) as total from orders 
        where status="A" 
        group by cust_id 
        order by total desc

$match 段階

フォーマット:

{ $match: { <query> } }

説明:

  • <query> MongoDBのクエリ条件

クエリ条件を設定するために使用します。$matchが無視された場合、すべてのデータのクエリを意味します。

ヒント: MongoDBのクエリ構文に馴染みがない場合は、以前の章を参照してください。

$group 段階

SQLのgroup by句に類似し、データをグループ化した後、グループ化されたデータに対して一連の統計計算を実行するために使用されます。

$group の基本的な使用方法

構文:

{
  $group:
    {
      _id: <expression>, // グループ化条件、例: どのフィールドでグループ化するか
      <field1>: { <accumulator1> : <expression1> },  // 集計操作、N個の集計操作を追加できます
      ...
    }
 }

説明:

  • - カスタム統計指標の名前、合計でN個ある可能性があります
  • - 集計関数、SQLのsum、avgなどの集計関数に似ていますが、MongoDBの集計関数はプレフィックスに$を付けたものです。例: $sum、$avg
  • - 集計関数のパラメータで、通常はカウントするフィールドの値です。ドキュメントのフィールドを参照する場合は"$field name"の形式を使用します

例:

db.orders.aggregate([
                     {
					 	$group: { 
							_id: "$cust_id",
							total: { $sum: "$amount" }, // 最初の計算指標であるtotalを追加し、$sumの合計演算子を使用
							amount_avg: {$avg: "$amount"}  // 2番目の計算指標であるavgを追加し、$avgの平均計算演算子を使用
						} 
					}
               ])

出力:

{ "_id" : "abc1", "total" : 75, "amount_avg" : 37.5 }
{ "_id" : "xyz1", "total" : 250, "amount_avg" : 83.33333333333333 }

同等なSQL:

select 
	sum(amount) as  total,
	avg(amount) as amount_avg
from orders 
group by cust_id

$group 集計関数

$group でよく使用される集計関数は以下の通りです:

Operator 説明
$avg 平均を計算する {$avg: "$amount"}
$sum 合計 {$sum: "$amount"}
$max 最大値 {$max: "$amount"}
$min 最小値 {$min: "$amount"}
$first グループ化後のデータを返す、最初のドキュメントの内容 {$first: "$amount"}
$last グループ化後のデータを返す、最後のドキュメントの内容 {$last: "$amount"}
$push グループ化後のデータを返す { $push: { ord_date: "$ord_date", amount: "$amount" }
$addToSet グループ化後のデータを返す、$push と異なり重複を取り除く { $addToSet: "$amount" }

$push の例

db.orders.aggregate(
   [
     {
       $group:
         {
           _id: "$cust_id",
           all: { $push: { ord_date: "$ord_date", amount: "$amount" } } // ord_date と amount フィールドの値
         }
     }
   ]
)

出力

{ "_id" : "abc1", "all" : [ { "ord_date" : "2021-04-18 00:00:00", "amount" : 50 }, { "ord_date" : "2021-04-21 00:00:00", "amount" : 25 } ] }
{ "_id" : "xyz1", "all" : [ { "ord_date" : "2021-04-18 00:00:00", "amount" : 100 }, { "ord_date" : "2021-04-20 00:00:00", "amount" : 25 }, { "ord_date" : "2021-04-21 00:00:00", "amount" : 125 } ] }

$addToSet の例

db.orders.aggregate(
   [
     {
       $group:
         {
           _id: "$cust_id",
           all_amount: { $addToSet: "$amount" } // すべての重複のない amount の値を返す
         }
     }
   ]
)

出力

{ "_id" : "abc1", "all_amount" : [ 25, 50 ] }
{ "_id" : "xyz1", "all_amount" : [ 100, 25, 125 ] }

$sort:

$sort ステージは通常、集計されたデータを並べ替えるために最後に配置されます。

フォーマット:

{ $sort: { <field1>: <sort order>, <field2>: <sort order> ... } }

説明:

  • , - 並べ替えるフィールドの名前、複数のフィールドをサポートします。
  • - 並べ替えの方向、降順には -1、昇順には 1 を使用します。

例:

db.orders.aggregate([
                     { $match: { status: "A" } },
                     { $group: { _id: "$cust_id", total: { $sum: "$amount" } } },
                     { $sort: { total: -1 } }
                   ])

集計ページネーション

$limit および $skip オペレータを使用してページネーションを実装できます。

例:

db.orders.aggregate([
                     { $match: { status: "A" } },
                     { $group: { _id: "$cust_id", total: { $sum: "$amount" } } },
                     { $sort: { total: -1 } },
					 { $limit: 5 }, // 返されるレコードの数を制限します、ページネーションのページサイズに類似しています。
					 { $skip: 1 } // 一定数のレコードをスキップします、SQL のオフセットに類似しています。
                   ])