定義
$group$group ステージは、グループ キーに従って、同じフィールドまたは式を持つ複数のドキュメントを単一のドキュメントに結合します。その結果、一意のグループ キーごとに 1 つのドキュメントが生成されます。
グループキーは、多くの場合、フィールドまたはフィールドのグループです。グループキーは、式の結果にすることもできます。グループキーを設定するには、
$groupパイプライン ステージの_idフィールドを使用します。の使用例については以下を参照してください。$groupステージの出力では、_idフィールドにそのドキュメントのグループ キーが設定されます。出力ドキュメントには、アキュムレータ式 を使用して設定された追加のフィールドを含めることもできます。
注意
$groupは出力ドキュメントを順序付けしません。
互換性
次の環境でホストされる配置には $group を使用できます。
MongoDB Atlas はクラウドでの MongoDB 配置のためのフルマネージド サービスです
MongoDB Enterprise: サブスクリプションベースの自己管理型 MongoDB バージョン
MongoDB Community: ソースが利用可能で、無料で使用できる自己管理型の MongoDB のバージョン
構文
$groupステージのプロトタイプ形式は次のとおりです。
{ $group: { _id: <expression>, // Group key <field1>: { <accumulator1> : <expression1> }, ... } }
フィールド | 説明 |
|---|---|
| 必須。 |
|
_id演算子とアキュムレータ 演算子は、有効な任意のexpressionを受け入れることができます。 式の詳細については、「式 」を参照してください。
Considerations
パフォーマンス
$group はブロッキング ステージであり、パイプラインはデータを処理する前にすべての入力データが検索されるまで待機します。ブロッキング ステージは、複数のステージを持つパイプラインの並列処理を減らすため、パフォーマンスを低下させる可能性があります。ブロッキング ステージでは、大規模なデータセットに対して大量のメモリが使用される場合もあります。
アキュムレータ演算子
<accumulator> 演算子は、次のアキュムレータ 演算子のいずれかである必要があります。
名前 | 説明 |
|---|---|
ユーザー定義のアキュムレータ関数の結果を返します。 | |
グループごとのユニークな式値の配列を返します。配列要素の順序は未定義です。 バージョン 5.0 で変更、 | |
数値の平均を返します。数値以外の値は無視されます。 バージョン 5.0 で変更、 | |
グループにあるドキュメントの数を返します。
バージョン 5.0 で追加され、 | |
グループ内の最初のドキュメントの式の結果を返します。 バージョン 5.0 で変更、 | |
グループ内の最初の バージョン 5.2 で追加され、 | |
グループ内の最後のドキュメントの式の結果を返します。 バージョン 5.0 で変更、 | |
グループ内の最後の バージョン 5.2 で追加され、 | |
グループごとの最大の式の値を返します。 バージョン 5.0 で変更、 | |
グループ内の最大値を持つ バージョン 5.2 で追加。 | |
各グループの入力ドキュメントを組み合わせて作成したドキュメントを返します。 | |
グループごとの最小の式値を返します。 バージョン 5.0 で変更、 | |
グループごとのドキュメントの式値の配列を返します。 バージョン 5.0 で変更、 | |
入力値の母集団標準偏差を返します。 バージョン 5.0 で変更、 | |
入力値のサンプル標準偏差を返します。 バージョン 5.0 で変更、 | |
数値の合計を返します。数値以外の値は無視されます。 バージョン 5.0 で変更、 | |
$group およびメモリ制限
$groupステージが100メガバイトの RAM を超える場合、MongoDB は一時ファイルにデータを書込みます。 ただし、 allowDiskUseオプションがfalseに設定されている場合、 $groupはエラーを返します。 詳細については、「集計パイプラインの制限 」を参照してください。
$group パフォーマンスの最適化
このセクションでは、 $groupのパフォーマンスを向上させるための最適化について説明します。 手動で行うことができる最適化と、MongoDB が内部で行う最適化があります。
各グループの最初または最後のドキュメントを返すための最適化
パイプラインsortsとgroupsが同じフィールドで実行され、 $groupステージで$firstまたは$lastアキュムレータ 演算子のみが使用される場合は、並べ替え順序に一致するグループ化されたフィールドにインデックスを追加することを検討してください。場合によっては、$group ステージでインデックスを使用して各グループの最初または最後のドキュメントをすばやく見つけることができます。
例
moviesコレクションにインデックス{ year: 1, title: 1 } が含まれている場合、次のパイプラインはそのインデックスを使用して各グループの最初のドキュメントを検索できます。
db.movies.aggregate([ { $sort: { year: 1, title: 1 } }, { $group: { _id: { year: "$year" }, title: { $first: "$title" } } } ])
スロットベースのクエリ実行エンジン
バージョン 5.2 以降、MongoDB は、次のいずれかの場合にスロットベースの実行クエリ エンジンを使用して$groupステージを実行します。
$groupはパイプラインの第一ステージです。パイプラインの先行ステージもすべて、スロットベースの実行エンジンで実行できます。
詳細については、「$group 最適化」を参照してください。
例
コレクション内のドキュメント数のカウント
このページの例では、付属の sample_mflixサンプルデータセット のデータを使用します。このデータセットを自己管理型MongoDBデプロイにロードする 方法の詳細については、「サンプルデータセットをロードする 」を参照してください。サンプルデータベースに変更を加えた場合、このページの例を実行するには、データベースを削除して再作成する必要がある場合があります。
次の集計操作では、 $groupステージを使用してmoviesコレクション内のドキュメントの数をカウントします。
db.movies.aggregate([ { $group: { _id: null, count: { $count: {} } } } ])
[ { _id: null, count: 21349 } ]
この集計操作は、次の SQL ステートメントと同等です。
SELECT COUNT(*) AS count FROM movies
Retrieve Distinct Values
次の集計操作では、$group ステージを使用して、rated moviesコレクションから個別の 値を取得します。
db.movies.aggregate( [ { $group : { _id : "$rated" } } ] )
[ { _id: 'TV-PG' }, { _id: 'PG' }, { _id: 'TV-14' }, { _id: 'OPEN' }, { _id: 'Not Rated' }, { _id: 'GP' }, { _id: 'TV-Y7' }, { _id: 'G' }, { _id: 'PG-13' }, { _id: null }, { _id: 'M' }, { _id: 'R' }, { _id: 'TV-MA' }, { _id: 'APPROVED' }, { _id: 'PASSED' }, { _id: 'Approved' }, { _id: 'AO' }, { _id: 'TV-G' } ]
注意
$groupを使用してシャーディングされたコレクション内の個別の値を検索する場合、操作の結果が になると、結果にはDISTINCT_SCAN 孤立したドキュメント が含まれる可能性があります。
影響を受けるのはセカンダリが正しいパイプラインのみで、実質的に コマンドの論理的な同等性があります。パイプラインのdistinct $groupまたは 先頭あたりに ステージがあり、 の前には$group $sortステージはありません。 。
例、次の形式の $group 操作の場合、DISTINCT_SCAN が返されます。
{ $group : { _id : "$<field>" } }
個別の値を取得するための動作の詳細については、個別の コマンドの動作を参照してください。
操作の結果がDISTINCT_SCAN になるかどうかを確認するには、操作の explain 結果 を確認します。
評価でグループ化
次の集計操作では、ドキュメントを ratedフィールドでグループ化し、評価ごとの合計実行時間を計算し、合計実行時間が 100000 以上の評価のみを返します。
db.movies.aggregate( [ // First Stage { $group: { _id: "$rated", totalRuntime: { $sum: "$runtime" } } }, // Second Stage { $match: { "totalRuntime": { $gte: 100000 } } } ] )
[ { _id: 'PG-13', totalRuntime: 250843 }, { _id: 'R', totalRuntime: 582318 }, { _id: null, totalRuntime: 967127 }, { _id: 'PG', totalRuntime: 191204 } ]
- 第 1 ステージ:
$groupステージでは、ドキュメントをratedでグループ化し、個別の評価値を取得します。このステージでは、各評価グループのtotalRuntimeが返されます。- 第 2 ステージ:
- ステージでは、結果のドキュメントをフィルタリングして、
$matchtotalRuntime100000が 以上の評価のみを返します。
この集計操作は、次の SQL ステートメントと同等です。
SELECT rated, Sum(runtime) AS totalRuntime FROM movies GROUP BY rated HAVING totalRuntime >= 100000
Tip
件数、合計、および平均の計算
年ごとにグループ化
次のパイプラインは、1910 以前の各年の合計実行時間、平均実行時間、映画の本数
db.movies.aggregate([ { $match: { "year": { $lt: 1910 } } }, { $group: { _id: "$year", totalRuntime: { $sum: "$runtime" }, averageRuntime: { $avg: "$runtime" }, count: { $sum: 1 } } }, { $sort: { totalRuntime: -1 } } ])
[ { _id: 1909, totalRuntime: 14, averageRuntime: 14, count: 1 }, { _id: 1903, totalRuntime: 11, averageRuntime: 11, count: 1 }, { _id: 1896, totalRuntime: 2, averageRuntime: 1, count: 2 } ]
- 第 1 ステージ:
$matchステージでは、ドキュメントをフィルタリングして、1910 より前にリリースされた映画のみを次のステージに渡します。- 第 2 ステージ:
$groupステージでは、ドキュメントを年ごとにグループ化し、各グループの合計実行時間、平均実行時間、ドキュメントの合計数を計算します。- 第 3 ステージ:
$sortステージでは、各グループの合計実行時間の降順で結果がソートされます。
この集計操作は、次の SQL ステートメントと同等です。
SELECT year, Sum(runtime) AS totalRuntime, Avg(runtime) AS averageRuntime, Count(*) AS count FROM movies WHERE year < 1910 GROUP BY year ORDER BY totalRuntime DESC
Tip
db.collection.countDocuments()$group{$sum集計ステージを 式でラップする
グループ化 null
次の集計操作では、null のグループ _id を指定し、コレクション内のすべてのドキュメントの合計実行時間、平均実行時間、カウントを計算します。
db.movies.aggregate([ { $group: { _id: null, totalRuntime: { $sum: "$runtime" }, averageRuntime: { $avg: "$runtime" }, count: { $sum: 1 } } } ])
[ { _id: null, totalRuntime: 2167458, averageRuntime: 103.65652797704448, count: 21349 } ]
この集計操作は、次の SQL ステートメントと同等です。
SELECT Sum(runtime) AS totalRuntime, Avg(runtime) AS averageRuntime, Count(*) AS count FROM movies
Tip
db.collection.countDocuments()$group{$sum集計ステージを 式でラップする
Pivot Data
タイトルを年別にグループ化
次の集計操作では、moviesコレクションのデータをピボットして、タイトルを年ごとにグループ化します。
db.movies.aggregate([ { $match: { year: { $lt: 1910 } } }, { $group: { _id: "$year", titles: { $push: "$title" } } }, { $sort: { _id: 1 } } ])
[ { _id: 1896, titles: [ 'The Kiss', 'The Kiss' ] }, { _id: 1903, titles: [ 'The Great Train Robbery' ] }, { _id: 1909, titles: [ 'A Corner in Wheat' ] } ]
ドキュメントを年別にグループ化
次の集計操作では、ドキュメントを年ごとにグループ化します。
db.movies.aggregate([ { $match: { year: { $lt: 1910 } } }, { $group: { _id: "$year", movies: { $push: "$$ROOT" } } }, { $addFields: { totalRuntime: { $sum: "$movies.runtime" } } }, { $sort: { _id: 1 } } ])
[ { _id: 1896, movies: '...', totalRuntime: 2 }, { _id: 1903, movies: '...', totalRuntime: 11 }, { _id: 1909, movies: '...', totalRuntime: 14 } ]
- 第 1 ステージ:
$matchはドキュメントをフィルタリングして、1910 より前にリリースされた映画のみを次のステージに渡します。- 第 2 ステージ:
$groupは$$ROOTシステム変数を使用してドキュメント全体を年ごとにグループ化します。- 第 3 ステージ:
$addFields出力に各年の映画の合計実行時間を含むフィールドを追加します。注意
結果のドキュメントは、BSON ドキュメント サイズの上限である 16 メビバイトを超えてはなりません。
- 第 4 ステージ:
$sort_idは結果のドキュメントを で昇順にソートします。
このページのC#の例では、Atlasサンプルデータセット の sample_mflixデータベースを使用します。MongoDB Atlasクラスターを無料で作成して、サンプルデータセットをロードする方法については、 MongoDB .NET/ C#ドライバーのドキュメントの「 開始 」を参照してください。
次の Movie クラスは、sample_mflix.movies コレクション内のドキュメントをモデル化します。
public class Movie { public ObjectId Id { get; set; } public int Runtime { get; set; } public string Title { get; set; } public string Rated { get; set; } public List<string> Genres { get; set; } public string Plot { get; set; } public ImdbData Imdb { get; set; } public int Year { get; set; } public int Index { get; set; } public string[] Comments { get; set; } [] public DateTime LastUpdated { get; set; } }
注意
パスカルケースの ConventionPack
このページのC# クラスはプロパティ名にパスカルケースを使用していますが、MongoDB コレクションのフィールド名はキャメルケースを使用しています。この違いを考慮するために、アプリケーションが起動する際に次のコードを使用してConventionPackを登録してください。
var camelCaseConvention = new ConventionPack { new CamelCaseElementNameConvention() }; ConventionRegistry.Register("CamelCase", camelCaseConvention, type => true);
MongoDB .NET/ C#ドライバーを使用して$group ステージを集計パイプラインに追加するには、 PipelineDefinitionオブジェクトで Group() メソッドを呼び出します。
次の例では、ドキュメントを Ratedフィールドの値でグループ化するパイプラインステージを作成しています。各グループの評価は、各出力ドキュメントの Rating という名前のフィールドに表示されます。各出力ドキュメントには、TotalRuntime、MedianRuntime、NinetiethPercentileRuntime という名前のフィールドも含まれており、各グループの映画の合計、中央値、90 パーセンタイルの実行時間値が保存されます。
var pipeline = new EmptyPipelineDefinition<Movie>() .Group( id: m => m.Rated, group: g => new { Rating = g.Key, TotalRuntime = g.Sum(m => m.Runtime), MedianRuntime = g.Select(m => m.Runtime).Median(), NinetiethPercentileRuntime = g.Select(m => m.Runtime).Percentile(new[] { 0.9 }) } );
このページのNode.js の例では、Atlasサンプルデータセット の sample_mflixデータベースを使用します。無料のMongoDB Atlas cluster を作成し、サンプルデータセットをロードする方法については、 MongoDB Node.jsドライバーのドキュメントの開始を参照してください。
MongoDB Node.jsドライバーを使用して $group ステージを集計パイプラインに追加するには、パイプラインオブジェクトで $group 演算子を使用します。
次の例では、ドキュメントを ratedフィールドの値でグループ化するパイプラインステージを作成しています。各出力ドキュメントには、各グループの評価を保存する ratingフィールドが含まれています。各出力ドキュメントには、グループ内のすべての映画の合計ランタイムが保存される totalRuntime という名前のフィールドも含まれています。次に、この例では集計パイプラインを実行します。
const pipeline = [ { $group: { _id: "$rated", rating: { $first: "$rated" }, totalRuntime: { $sum: "$runtime" } } } ]; const cursor = collection.aggregate(pipeline); return cursor;
詳細
「グループと合計データ」のチュートリアルでは、 一般的なユースケースにおける $group 演算子の幅広い例を紹介します。
関連するパイプラインステージの詳細については、$addFieldsガイドを参照してください。