Docs Menu
Docs Home
/
MongoDBマニュアル
/ / /

$group(集計)

項目一覧

  • 定義
  • 互換性
  • 構文
  • Considerations
  • 追加リソース
$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

必須。 _id式はグループキーを指定します。_id null の 値またはその他の定数値を指定すると、$group ステージはすべての入力ドキュメントにわたる値を集計する単一のドキュメントを返します。 「 Null によるグループの例」を参照してください。

field

_idアキュムレータ 演算子は、有効な任意のexpressionを受け入れることができます。式の詳細については、式演算子を参照してください。

$group はブロッキング ステージであり、パイプラインはデータを処理する前にすべての入力データが検索されるまで待機します。ブロッキング ステージは、複数のステージを持つパイプラインの並列処理を減らすため、パフォーマンスを低下させる可能性があります。ブロッキング ステージでは、大規模なデータセットに対して大量のメモリが使用される場合もあります。

<accumulator> 演算子は、次のアキュムレータ 演算子のいずれかである必要があります。

バージョン 5.0 での変更

名前
説明

ユーザー定義のアキュムレータ関数の結果を返します。

グループごとのユニークな式値の配列を返します。配列要素の順序は未定義です。

バージョン 5.0 で変更$setWindowFieldsステージで使用可能です。

数値の平均を返します。数値以外の値は無視されます。

バージョン 5.0 で変更$setWindowFieldsステージで使用可能です。

指定ソート順に従って、グループ内の最下位の要素を返します。

バージョン 5.2 で追加

$groupおよび$setWindowFieldsステージで利用可能です。

グループ内の下位 n フィールドの集計を、指定のソート順序に従って返します。

バージョン 5.2 で追加

$groupおよび$setWindowFieldsステージで利用可能です。

グループにあるドキュメントの数を返します。

$count パイプライン ステージとは異なります。

バージョン 5.0 で追加され、$groupおよび$setWindowFieldsステージで利用できます。

グループ内の最初のドキュメントのの結果を返します。

バージョン 5.0 で変更$setWindowFieldsステージで使用可能です。

グループ内の最初の n 個の要素の集計を返します。ドキュメントが定義どおりの順序になっている場合にのみ意味があります。$firstN 配列演算子とは異なります。

バージョン 5.2 で追加され$group$setWindowFieldsステージで使用できます。

グループ内の最後のドキュメントのの結果を返します。

バージョン 5.0 で変更$setWindowFieldsステージで使用可能です。

グループ内の最後の n 要素の集計を返します。ドキュメントが定義どおりの順序になっている場合にのみ意味があります。$lastN 配列演算子とは異なります。

バージョン 5.2 で追加され$group$setWindowFieldsステージで使用できます。

グループごとの最大の式の値を返します。

バージョン 5.0 で変更$setWindowFieldsステージで使用可能です。

グループ内の最大値を持つ n 要素の集計を返します。$maxN 配列演算子とは異なります。

バージョン 5.2 で追加

$group$setWindowFields 、および式 として使用できます。

中央値、つまり 50 パーセンタイルの近似値がスカラー値として返されます。

バージョン 7.0 で追加

この演算子は、次に示すステージでアキュムレータとして使用できます。

集計式としても使用できます。

各グループの入力ドキュメントを組み合わせて作成したドキュメントを返します。

グループごとの最小の式値を返します。

バージョン 5.0 で変更$setWindowFieldsステージで使用可能です。

グループ内の n 個の最小値要素の集合を返します。$minN配列演算子とは異なります。

バージョン 5.2 で追加

$group$setWindowFields 、および式 として使用できます。

指定パーセンタイル値に対応するスカラー値の配列を返します。

バージョン 7.0 で追加

この演算子は、次に示すステージでアキュムレータとして使用できます。

集計式としても使用できます。

グループごとのドキュメントの式値の配列を返します。

バージョン 5.0 で変更$setWindowFieldsステージで使用可能です。

入力値の母集団標準偏差を返します。

バージョン 5.0 で変更$setWindowFieldsステージで使用可能です。

入力値のサンプル標準偏差を返します。

バージョン 5.0 で変更$setWindowFieldsステージで使用可能です。

数値の合計を返します。数値以外の値は無視されます。

バージョン 5.0 で変更$setWindowFieldsステージで使用可能です。

指定ソート順に従って、グループ内の最上位の要素を返します。

バージョン 5.2 で追加

$groupおよび$setWindowFieldsステージで利用可能です。

グループ内の上位 n フィールドの集計を、指定のソート順序に従って返します。

バージョン 5.2 で追加

$groupおよび$setWindowFieldsステージで利用可能です。

$groupステージが100メガバイトの RAM を超える場合、MongoDB は一時ファイルにデータを書込みます。 ただし、 allowDiskUseオプションがfalseに設定されている場合、 $groupはエラーを返します。 詳細については、「集計パイプラインの制限 」を参照してください。

このセクションでは、 $groupのパフォーマンスを向上させるための最適化について説明します。 手動で行うことができる最適化と、MongoDB が内部で行う最適化があります。

パイプラインsortsgroupsが同じフィールドで実行され、 $groupステージで$firstまたは$lastアキュムレータ 演算子のみが使用される場合は、並べ替え順序に一致するグループ化されたフィールドにインデックスを追加することを検討してください。場合によっては、$group ステージでインデックスを使用して各グループの最初または最後のドキュメントをすばやく見つけることができます。

foo という名前のコレクションにインデックス { x: 1, y: 1 } が含まれている場合、次のパイプラインはそのインデックスを使用して各グループの最初のドキュメントを検索できます。

db.foo.aggregate([
{
$sort:{ x : 1, y : 1 }
},
{
$group: {
_id: { x : "$x" },
y: { $first : "$y" }
}
}
])

バージョン 5.2 以降、MongoDB は、次のいずれかの場合にスロットベースの実行クエリ エンジンを使用して$groupステージを実行します。

  • $group はパイプラインの第一ステージです。

  • パイプラインの先行ステージもすべて、スロットベースの実行エンジンで実行できます。

詳細については、「$group 最適化」を参照してください。

mongoshでは、次のドキュメントを含むsalesという名前のサンプル コレクションが作成されます。

db.sales.insertMany([
{ "_id" : 1, "item" : "abc", "price" : Decimal128("10"), "quantity" : Int32("2"), "date" : ISODate("2014-03-01T08:00:00Z") },
{ "_id" : 2, "item" : "jkl", "price" : Decimal128("20"), "quantity" : Int32("1"), "date" : ISODate("2014-03-01T09:00:00Z") },
{ "_id" : 3, "item" : "xyz", "price" : Decimal128("5"), "quantity" : Int32( "10"), "date" : ISODate("2014-03-15T09:00:00Z") },
{ "_id" : 4, "item" : "xyz", "price" : Decimal128("5"), "quantity" : Int32("20") , "date" : ISODate("2014-04-04T11:21:39.736Z") },
{ "_id" : 5, "item" : "abc", "price" : Decimal128("10"), "quantity" : Int32("10") , "date" : ISODate("2014-04-04T21:23:13.331Z") },
{ "_id" : 6, "item" : "def", "price" : Decimal128("7.5"), "quantity": Int32("5" ) , "date" : ISODate("2015-06-04T05:08:13Z") },
{ "_id" : 7, "item" : "def", "price" : Decimal128("7.5"), "quantity": Int32("10") , "date" : ISODate("2015-09-10T08:43:00Z") },
{ "_id" : 8, "item" : "abc", "price" : Decimal128("10"), "quantity" : Int32("5" ) , "date" : ISODate("2016-02-06T20:20:13Z") },
])

次の集計操作では、 $groupステージを使用してsalesコレクション内のドキュメントの数をカウントします。

db.sales.aggregate( [
{
$group: {
_id: null,
count: { $count: { } }
}
}
] )

この操作では、次の結果を返します。

{ "_id" : null, "count" : 8 }

この集計操作は、次の SQL ステートメントと同等です。

SELECT COUNT(*) AS count FROM sales

Tip

以下も参照してください。

次の集計操作では、 $groupステージを使用して、 salesコレクションから個別のアイテム値を取得します。

db.sales.aggregate( [ { $group : { _id : "$item" } } ] )

この操作では、次の結果を返します。

{ "_id" : "abc" }
{ "_id" : "jkl" }
{ "_id" : "def" }
{ "_id" : "xyz" }

注意

$groupを使用して シャーディングされたシャーディングされたコレクション内の個別の値を検索する場合、操作の結果が になると、結果にはDISTINCT_SCAN 孤立したドキュメント が含まれる可能性があります。

The only semantically correct パイプライン that is impacted is effectively a logical equivalent of a command, where there isdistinct a$group stage at or near the beginning of the パイプライン and the$group is not preceded by a stage$sort

例、次の形式の $group 操作では DISTINCT_SCAN が生成されます。

{ $group : { _id : "$<field>" } }

個別の値を取得するための動作の詳細については、個別の コマンドの動作を参照してください。

操作の結果がDISTINCT_SCAN になるかどうかを確認するには、操作の explain 結果 を確認します。

次の集計操作では、item フィールドでドキュメントをグループ化し、アイテムごとの合計売上額を計算し、合計売上額が 100 以上のアイテムのみを返します。

db.sales.aggregate(
[
// First Stage
{
$group :
{
_id : "$item",
totalSaleAmount: { $sum: { $multiply: [ "$price", "$quantity" ] } }
}
},
// Second Stage
{
$match: { "totalSaleAmount": { $gte: 100 } }
}
]
)
第 1 ステージ:
$groupステージでは、ドキュメントをitemでグループ化し、個別のアイテム値を取得します。 このステージでは、各アイテムのtotalSaleAmountが返されます。
第 2 ステージ:
$match ステージでは、結果のドキュメントをフィルタリングして、totalSaleAmount が 100 以上のアイテムのみを返します。

この操作では、次の結果を返します。

{ "_id" : "abc", "totalSaleAmount" : Decimal128("170") }
{ "_id" : "xyz", "totalSaleAmount" : Decimal128("150") }
{ "_id" : "def", "totalSaleAmount" : Decimal128("112.5") }

この集計操作は、次の SQL ステートメントと同等です。

SELECT item,
Sum(( price * quantity )) AS totalSaleAmount
FROM sales
GROUP BY item
HAVING totalSaleAmount >= 100

Tip

以下も参照してください。

mongoshでは、次のドキュメントを含むsalesという名前のサンプル コレクションが作成されます。

db.sales.insertMany([
{ "_id" : 1, "item" : "abc", "price" : Decimal128("10"), "quantity" : Int32("2"), "date" : ISODate("2014-03-01T08:00:00Z") },
{ "_id" : 2, "item" : "jkl", "price" : Decimal128("20"), "quantity" : Int32("1"), "date" : ISODate("2014-03-01T09:00:00Z") },
{ "_id" : 3, "item" : "xyz", "price" : Decimal128("5"), "quantity" : Int32( "10"), "date" : ISODate("2014-03-15T09:00:00Z") },
{ "_id" : 4, "item" : "xyz", "price" : Decimal128("5"), "quantity" : Int32("20") , "date" : ISODate("2014-04-04T11:21:39.736Z") },
{ "_id" : 5, "item" : "abc", "price" : Decimal128("10"), "quantity" : Int32("10") , "date" : ISODate("2014-04-04T21:23:13.331Z") },
{ "_id" : 6, "item" : "def", "price" : Decimal128("7.5"), "quantity": Int32("5" ) , "date" : ISODate("2015-06-04T05:08:13Z") },
{ "_id" : 7, "item" : "def", "price" : Decimal128("7.5"), "quantity": Int32("10") , "date" : ISODate("2015-09-10T08:43:00Z") },
{ "_id" : 8, "item" : "abc", "price" : Decimal128("10"), "quantity" : Int32("5" ) , "date" : ISODate("2016-02-06T20:20:13Z") },
])

以下のパイプラインは、2014 年の各日の合計売上額、平均売上数量、売上件数を計算します。

db.sales.aggregate([
// First Stage
{
$match : { "date": { $gte: new ISODate("2014-01-01"), $lt: new ISODate("2015-01-01") } }
},
// Second Stage
{
$group : {
_id : { $dateToString: { format: "%Y-%m-%d", date: "$date" } },
totalSaleAmount: { $sum: { $multiply: [ "$price", "$quantity" ] } },
averageQuantity: { $avg: "$quantity" },
count: { $sum: 1 }
}
},
// Third Stage
{
$sort : { totalSaleAmount: -1 }
}
])
第 1 ステージ:
$match ステージでは、ドキュメントをフィルタリングして、2014 年のドキュメントのみを次のステージに渡します。
第 2 ステージ:
$group ステージでは、ドキュメントを日付別にグループ化し、各グループの合計販売額、平均数量、およびドキュメントの合計数を計算します。
第 3 ステージ:
$sort ステージでは、各グループの合計売上額の降順で結果をソートします。

この操作は次の結果を返します。

{
"_id" : "2014-04-04",
"totalSaleAmount" : Decimal128("200"),
"averageQuantity" : 15, "count" : 2
}
{
"_id" : "2014-03-15",
"totalSaleAmount" : Decimal128("50"),
"averageQuantity" : 10, "count" : 1
}
{
"_id" : "2014-03-01",
"totalSaleAmount" : Decimal128("40"),
"averageQuantity" : 1.5, "count" : 2
}

この集計操作は、次の SQL ステートメントと同等です。

SELECT date,
Sum(( price * quantity )) AS totalSaleAmount,
Avg(quantity) AS averageQuantity,
Count(*) AS Count
FROM sales
WHERE date >= '01/01/2014' AND date < '01/01/2015'
GROUP BY date
ORDER BY totalSaleAmount DESC

Tip

以下も参照してください。

次の集計操作では、null のグループ _id を指定して、コレクション内のすべてのドキュメントの合計売上額、平均数量、および件数を計算します。

db.sales.aggregate([
{
$group : {
_id : null,
totalSaleAmount: { $sum: { $multiply: [ "$price", "$quantity" ] } },
averageQuantity: { $avg: "$quantity" },
count: { $sum: 1 }
}
}
])

この操作では、次の結果を返します。

{
"_id" : null,
"totalSaleAmount" : Decimal128("452.5"),
"averageQuantity" : 7.875,
"count" : 8
}

この集計操作は、次の SQL ステートメントと同等です。

SELECT Sum(price * quantity) AS totalSaleAmount,
Avg(quantity) AS averageQuantity,
Count(*) AS Count
FROM sales

Tip

以下も参照してください。

mongoshでは、次のドキュメントを含むbooksという名前のサンプル コレクションが作成されます。

db.books.insertMany([
{ "_id" : 8751, "title" : "The Banquet", "author" : "Dante", "copies" : 2 },
{ "_id" : 8752, "title" : "Divine Comedy", "author" : "Dante", "copies" : 1 },
{ "_id" : 8645, "title" : "Eclogues", "author" : "Dante", "copies" : 2 },
{ "_id" : 7000, "title" : "The Odyssey", "author" : "Homer", "copies" : 10 },
{ "_id" : 7020, "title" : "Iliad", "author" : "Homer", "copies" : 10 }
])

次の集計操作では、books コレクションのデータをピボットして、タイトルを著者ごとにグループ化します。

db.books.aggregate([
{ $group : { _id : "$author", books: { $push: "$title" } } }
])

この操作により、次のドキュメントが返されます。

{ "_id" : "Homer", "books" : [ "The Odyssey", "Iliad" ] }
{ "_id" : "Dante", "books" : [ "The Banquet", "Divine Comedy", "Eclogues" ] }

次の集計操作はドキュメントを author ごとにグループ化します。

db.books.aggregate([
// First Stage
{
$group : { _id : "$author", books: { $push: "$$ROOT" } }
},
// Second Stage
{
$addFields:
{
totalCopies : { $sum: "$books.copies" }
}
}
])
第 1 ステージ:

$group$$ROOTシステム変数を使用して、ドキュメント全体を著者ごとにグループ化します。 このステージでは、次のドキュメントを次のステージに渡します。

{ "_id" : "Homer",
"books" :
[
{ "_id" : 7000, "title" : "The Odyssey", "author" : "Homer", "copies" : 10 },
{ "_id" : 7020, "title" : "Iliad", "author" : "Homer", "copies" : 10 }
]
},
{ "_id" : "Dante",
"books" :
[
{ "_id" : 8751, "title" : "The Banquet", "author" : "Dante", "copies" : 2 },
{ "_id" : 8752, "title" : "Divine Comedy", "author" : "Dante", "copies" : 1 },
{ "_id" : 8645, "title" : "Eclogues", "author" : "Dante", "copies" : 2 }
]
}
第 2 ステージ:

$addFields 出力に各著者の書籍の合計部数を含むフィールドを追加します。

注意

結果のドキュメントは、BSON ドキュメント サイズの制限である 16 メガバイトを超えてはなりません。

この操作により、次のドキュメントが返されます。

{
"_id" : "Homer",
"books" :
[
{ "_id" : 7000, "title" : "The Odyssey", "author" : "Homer", "copies" : 10 },
{ "_id" : 7020, "title" : "Iliad", "author" : "Homer", "copies" : 10 }
],
"totalCopies" : 20
}
{
"_id" : "Dante",
"books" :
[
{ "_id" : 8751, "title" : "The Banquet", "author" : "Dante", "copies" : 2 },
{ "_id" : 8752, "title" : "Divine Comedy", "author" : "Dante", "copies" : 1 },
{ "_id" : 8645, "title" : "Eclogues", "author" : "Dante", "copies" : 2 }
],
"totalCopies" : 5
}

Tip

以下も参照してください。

郵便番号データセットによる集計チュートリアルでは、一般的なユースケースにおける$group演算子の幅広い例を紹介しています。

戻る

$graphLookup