MongoDB
 Computer >> コンピューター >  >> プログラミング >> MongoDB

MongoDBの集計(アグリゲーション)で配列要素を最大値と照合してグループ化する方法

MongoDBで、配列内の要素をその配列の最大値と照合し、結果をグループ化して集計したいケースはよくあります。そのような場合は、$group$maxを組み合わせた集計パイプライン(アグリゲーションフレームワーク)を使用します。ここでは、サンプルコレクションを作成しながら、具体的な手順をわかりやすく解説します。

1. サンプルコレクションの作成

まず、insertOne()メソッドを使って、detailsという配列フィールド(NameとScoreを持つオブジェクトのリスト)を含むドキュメントを3件挿入します。

> db.demo510.insertOne(
... {
...    details:[
...       {
...          Name:"Chris",
...          Score:56
...       },
...       {
...          Name:"David",
...          Score:45
...       }
...    ]
... }
... );
{
   "acknowledged" : true,
   "insertedId" : ObjectId("5e8845fa987b6e0e9d18f582")
}
> db.demo510.insertOne(
... {
...    details:[
...       {
...          Name:"Chris",
...          Score:56
...       },
...       {
...          Name:"David",
...          Score:47
...       }
...    ]
... }
... );
{
   "acknowledged" : true,
   "insertedId" : ObjectId("5e8845fb987b6e0e9d18f583")
}
> db.demo510.insertOne(
... {
...    details:[
...       {
...          Name:"Chris",
...          Score:45
...       },
...       {
...          Name:"David",
...          Score:91
...       }
...    ]
... }
... );
{
   "acknowledged" : true,
   "insertedId" : ObjectId("5e8845fb987b6e0e9d18f584")
}

2. 挿入したドキュメントの確認

find()メソッドを使って、コレクション内のすべてのドキュメントを表示してみましょう。

> db.demo510.find();

実行すると、次のような出力が得られます。

{ "_id" : ObjectId("5e8845fa987b6e0e9d18f582"), "details" : [ { "Name" : "Chris", "Score" : 56 },
{ "Name" : "David", "Score" : 45 } ] }
{ "_id" : ObjectId("5e8845fb987b6e0e9d18f583"), "details" : [ { "Name" : "Chris", "Score" : 56 },
{ "Name" : "David", "Score" : 47 } ] }
{ "_id" : ObjectId("5e8845fb987b6e0e9d18f584"), "details" : [ { "Name" : "Chris", "Score" : 45 },
{ "Name" : "David", "Score" : 91 } ] }

3. 最大値と一致する配列要素を抽出してグループ化するクエリ

続いて、集計パイプラインで「各ドキュメントのdetails配列の中から、Scoreが最大値と一致する要素を取り出し、そのNameごとにグループ化して件数を数える」クエリを見ていきましょう。

> db.demo510.aggregate([
... { "$project": {
...    "details": {
...        "$arrayElemAt": [
...            { "$filter": {
...                "input": "$details",
...                "as": "res",
...                "cond": {
...                    "$eq": [
...                        "$$res.Score",
...                        { "$max": {
...                            "$map": {
...                                "input": "$details",
...                                "as": "out",
...                                "in": "$$out.Score"
...                            }
...                        }}
...                    ]
...                }
...            }},
...            0
...        ]
...    }
... }},
... { "$group": {
...    "_id": "$details.Name",
...    "Name": { "$first": "$details.Name" },
...    "count": { "$sum": 1 }
... }}
... ])

このクエリを実行すると、次の結果が出力されます。

{ "_id" : "David", "Name" : "David", "count" : 1 }
{ "_id" : "Chris", "Name" : "Chris", "count" : 2 }

4. クエリのポイント解説

このパイプラインは、主に次の演算子を組み合わせて動作しています。

  • $map:details配列からScoreの値だけを取り出します。
  • $max:取り出したScoreの一覧から最大値を算出します。
  • $filter:Scoreが最大値と等しい($eq)要素だけを配列から抽出します。
  • $arrayElemAt:抽出された配列の先頭要素(インデックス0)を取得します。
  • $group:取り出した要素のNameをキーとしてグループ化し、$sumで該当ドキュメントの件数をカウントします。Nameの値は$firstで取得しています。

5. 結果の読み方

実行結果から、以下のことが読み取れます。

  • 3番目のドキュメントではDavidのスコア(91)が最大だったため、「David」が1件としてカウントされています。
  • 1番目と2番目のドキュメントではChrisのスコア(56)が最大だったため、「Chris」が2件としてカウントされています。

このように、$filter・$map・$max・$arrayElemAt・$groupを組み合わせることで、「配列内で最大値を持つ要素」を基準にしたグループ集計をシンプルに実現できます。テストの最高得点者や売上トップ商品など、配列データから最大値に関連する情報を集計したい場面でぜひ活用してください。

  1. JavaScriptで配列の最大値を取得する方法:Math.max()とsort()の使い方を徹底解説

    JavaScriptでは、Math.max()関数とsort()メソッドを活用することで、配列の中から最大値を簡単に見つけることができます。本記事では、それぞれの方法について具体的なサンプルコードとともにわかりやすく解説します。 1) Math.max()を使う方法 Math.max()は、引数として渡された複数の値の中から最大値を返す組み込み関数です。apply()メソッドと組み合わせることで、配列のすべての要素を一つずつ精査し、その中で最大の値を取得できます。以下の例で具体的な使い方を見ていきましょう。 コード例 <html> <body> <script&g

  2. JavaScriptで配列の要素を同じ配列内に複製する方法

    JavaScriptでは、concat()メソッドとsort()メソッドを組み合わせることで、既存の配列の要素を同じ配列内に複製することができます。ここでは、実際に動作するサンプルコードを使って、その手順をわかりやすく解説します。 コード例 以下は、配列の要素を同じ配列内に複製するためのコード例です。 <!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8" /> <meta name="viewport" cont