定義
Considerations
$bucket およびメモリ制限
$bucketステージには100 メガバイトのRAM制限があります。デフォルトでは 、 ステージがこの制限を超えると、$bucket はエラーを返します。ステージ処理のより多くのスペースを確保するには、 allowDiskUse オプションを使用して集計パイプラインライン ステージが一時ファイルにデータを書込むようにします。
Tip
構文
{ $bucket: { groupBy: <expression>, boundaries: [ <lowerbound1>, <lowerbound2>, ... ], default: <literal>, output: { <output1>: { <$accumulator expression> }, ... <outputN>: { <$accumulator expression> } } } }
The $bucket document contains the following fields:
フィールド | タイプ | 説明 | |||
|---|---|---|---|---|---|
式 | ドキュメントをグループ化するための式。フィールドパスを指定するには、フィールド名の前にドル記号( Unless | ||||
配列 | An array of values based on the groupBy expression that specify the boundaries for each bucket. Each adjacent pair of values acts as the inclusive lower boundary and the exclusive upper boundary for the bucket. You must specify at least two boundaries. 指定する値は昇順で、すべて同じ型である必要があります。ただし、値が次のような混合数値型である場合を除きます。
例、
| ||||
literal | Optional. A literal that specifies the 指定しない場合、各入力ドキュメントは
| ||||
ドキュメント | 省略可能。
|
動作
$bucket では以下の条件の 1 つ以上が満たされる必要があります。そうでない場合、操作でエラーがスローされます。
groupBy 式が配列またはドキュメントに変換される場合、$bucket は $sort の比較ロジックを使用して入力ドキュメントをバケットに配置します。
例
年別バケットと バケット結果に基づくフィルタリング
In mongosh, create a sample collection named artists with the following documents:
db.artists.insertMany([ { "_id" : 1, "last_name" : "Bernard", "first_name" : "Emil", "year_born" : 1868, "year_died" : 1941, "nationality" : "France" }, { "_id" : 2, "last_name" : "Rippl-Ronai", "first_name" : "Joszef", "year_born" : 1861, "year_died" : 1927, "nationality" : "Hungary" }, { "_id" : 3, "last_name" : "Ostroumova", "first_name" : "Anna", "year_born" : 1871, "year_died" : 1955, "nationality" : "Russia" }, { "_id" : 4, "last_name" : "Van Gogh", "first_name" : "Vincent", "year_born" : 1853, "year_died" : 1890, "nationality" : "Holland" }, { "_id" : 5, "last_name" : "Maurer", "first_name" : "Alfred", "year_born" : 1868, "year_died" : 1932, "nationality" : "USA" }, { "_id" : 6, "last_name" : "Munch", "first_name" : "Edvard", "year_born" : 1863, "year_died" : 1944, "nationality" : "Norway" }, { "_id" : 7, "last_name" : "Redon", "first_name" : "Odilon", "year_born" : 1840, "year_died" : 1916, "nationality" : "France" }, { "_id" : 8, "last_name" : "Diriks", "first_name" : "Edvard", "year_born" : 1855, "year_died" : 1930, "nationality" : "Norway" } ])
次の操作では、year_born フィールドに従ってドキュメントをバケットにグループ化し、バケット内のドキュメント数に基づいてフィルタリングします。
db.artists.aggregate( [ // First Stage { $bucket: { groupBy: "$year_born", // Field to group by boundaries: [ 1840, 1850, 1860, 1870, 1880 ], // Boundaries for the buckets default: "Other", // Bucket ID for documents which do not fall into a bucket output: { // Output for each bucket "count": { $sum: 1 }, "artists" : { $push: { "name": { $concat: [ "$first_name", " ", "$last_name"] }, "year_born": "$year_born" } } } } }, // Second Stage { $match: { count: {$gt: 3} } } ] )
- 第 1 ステージ
The
$bucketstage groups the documents into buckets by theyear_bornfield. The buckets have the following boundaries:[1840, 1850) は下限
1840を包含し、上限1850を除外します。[1850, 1860) は、下限
1850を包含し、上限1860を除外します。[1860, 1870) は、下限
1860を包含し、上限1870を除外します。[1870, 1880) は、下限
1870を包含し、上限1880を除外します。If a document did not contain the
year_bornfield or itsyear_bornfield was outside the ranges above, it would be placed in the default bucket with the_idvalue"Other".
このステージには、返すフィールドを決定するための出力ドキュメントが含まれます。
フィールド説明_idバケットの下限を含みます。
countバケット内のドキュメント数。
artistsバケット内の各アーティストに関する情報が記載されているドキュメントの配列。各ドキュメントにはアーティストに関する次の情報が記載されています。
nameは、アーティストのfirst_nameとlast_nameの連結($concat)を含みます。year_born
このステージでは、次のドキュメントを次のステージに渡します。
{ "_id" : 1840, "count" : 1, "artists" : [ { "name" : "Odilon Redon", "year_born" : 1840 } ] } { "_id" : 1850, "count" : 2, "artists" : [ { "name" : "Vincent Van Gogh", "year_born" : 1853 }, { "name" : "Edvard Diriks", "year_born" : 1855 } ] } { "_id" : 1860, "count" : 4, "artists" : [ { "name" : "Emil Bernard", "year_born" : 1868 }, { "name" : "Joszef Rippl-Ronai", "year_born" : 1861 }, { "name" : "Alfred Maurer", "year_born" : 1868 }, { "name" : "Edvard Munch", "year_born" : 1863 } ] } { "_id" : 1870, "count" : 1, "artists" : [ { "name" : "Anna Ostroumova", "year_born" : 1871 } ] } - 第 2 ステージ
$matchステージでは、前のステージからの出力をフィルタリングして、3 つ以上のドキュメントを含むバケットのみが返されます。この操作を実行すると次のドキュメントが返されます。
{ "_id" : 1860, "count" : 4, "artists" : [ { "name" : "Emil Bernard", "year_born" : 1868 }, { "name" : "Joszef Rippl-Ronai", "year_born" : 1861 }, { "name" : "Alfred Maurer", "year_born" : 1868 }, { "name" : "Edvard Munch", "year_born" : 1863 } ] }
$facet と $bucket の併用による複数フィールドのバケット化
You can use the $facet stage to perform multiple $bucket aggregations in a single stage.
In mongosh, create a sample collection named artwork with the following documents:
db.artwork.insertMany([ { "_id" : 1, "title" : "The Pillars of Society", "artist" : "Grosz", "year" : 1926, "price" : Decimal128("199.99") }, { "_id" : 2, "title" : "Melancholy III", "artist" : "Munch", "year" : 1902, "price" : Decimal128("280.00") }, { "_id" : 3, "title" : "Dancer", "artist" : "Miro", "year" : 1925, "price" : Decimal128("76.04") }, { "_id" : 4, "title" : "The Great Wave off Kanagawa", "artist" : "Hokusai", "price" : Decimal128("167.30") }, { "_id" : 5, "title" : "The Persistence of Memory", "artist" : "Dali", "year" : 1931, "price" : Decimal128("483.00") }, { "_id" : 6, "title" : "Composition VII", "artist" : "Kandinsky", "year" : 1913, "price" : Decimal128("385.00") }, { "_id" : 7, "title" : "The Scream", "artist" : "Munch", "year" : 1893 /* No price*/ }, { "_id" : 8, "title" : "Blue Flower", "artist" : "O'Keefe", "year" : 1918, "price" : Decimal128("118.42") } ])
The following operation uses two $bucket stages within a $facet stage to create two groupings, one by price and the other by year:
db.artwork.aggregate( [ { $facet: { // Top-level $facet stage "price": [ // Output field 1 { $bucket: { groupBy: "$price", // Field to group by boundaries: [ 0, 200, 400 ], // Boundaries for the buckets default: "Other", // Bucket ID for documents which do not fall into a bucket output: { // Output for each bucket "count": { $sum: 1 }, "artwork" : { $push: { "title": "$title", "price": "$price" } }, "averagePrice": { $avg: "$price" } } } } ], "year": [ // Output field 2 { $bucket: { groupBy: "$year", // Field to group by boundaries: [ 1890, 1910, 1920, 1940 ], // Boundaries for the buckets default: "Unknown", // Bucket ID for documents which do not fall into a bucket output: { // Output for each bucket "count": { $sum: 1 }, "artwork": { $push: { "title": "$title", "year": "$year" } } } } } ] } } ] )
- 最初のファセット
最初のファセットは、入力ドキュメントを
priceでグループ化します。バケットには次の境界があります。[0, 200) は下限
0を包含し、上限200を除外します。[200, 400) は下限
200を包含し、上限400を除外します。「その他」は
defaultバケットで、価格がないか、上記の範囲外の価格のドキュメントを含みます。
The
$bucketstage includes the output document to determine the fields to return:フィールド説明_idバケットの下限を含みます。
countバケット内のドキュメント数。
artworkバケット内の各アート作品に関する情報を含むドキュメントの配列。
averagePrice$avg演算子を使用して、バケット内のすべてのアート作品の平均価格を表示します。- 2 番目のファセット
2 番目のファセットでは、入力ドキュメントを
yearでグループ化します。バケットには次の境界があります。[1890、1910) は、下限
1890を包含し、上限1910を除外します。[1910, 1920) は、下限
1910を包含し、上限1920を除外します。[1920, 1940) は、下限
1910を包含し、上限1940を除外します。「不明」は
defaultバケットで、年数がないか、上記の範囲外の年数であるドキュメントを含みます。
The
$bucketstage includes the output document to determine the fields to return:フィールド説明countバケット内のドキュメント数。
artworkバケット内の各アート作品に関する情報を含むドキュメントの配列。
- 出力
この操作を実行すると次のドキュメントが返されます。
{ "price" : [ // Output of first facet { "_id" : 0, "count" : 4, "artwork" : [ { "title" : "The Pillars of Society", "price" : Decimal128("199.99") }, { "title" : "Dancer", "price" : Decimal128("76.04") }, { "title" : "The Great Wave off Kanagawa", "price" : Decimal128("167.30") }, { "title" : "Blue Flower", "price" : Decimal128("118.42") } ], "averagePrice" : Decimal128("140.4375") }, { "_id" : 200, "count" : 2, "artwork" : [ { "title" : "Melancholy III", "price" : Decimal128("280.00") }, { "title" : "Composition VII", "price" : Decimal128("385.00") } ], "averagePrice" : Decimal128("332.50") }, { // Includes documents without prices and prices greater than 400 "_id" : "Other", "count" : 2, "artwork" : [ { "title" : "The Persistence of Memory", "price" : Decimal128("483.00") }, { "title" : "The Scream" } ], "averagePrice" : Decimal128("483.00") } ], "year" : [ // Output of second facet { "_id" : 1890, "count" : 2, "artwork" : [ { "title" : "Melancholy III", "year" : 1902 }, { "title" : "The Scream", "year" : 1893 } ] }, { "_id" : 1910, "count" : 2, "artwork" : [ { "title" : "Composition VII", "year" : 1913 }, { "title" : "Blue Flower", "year" : 1918 } ] }, { "_id" : 1920, "count" : 3, "artwork" : [ { "title" : "The Pillars of Society", "year" : 1926 }, { "title" : "Dancer", "year" : 1925 }, { "title" : "The Persistence of Memory", "year" : 1931 } ] }, { // Includes documents without a year "_id" : "Unknown", "count" : 1, "artwork" : [ { "title" : "The Great Wave off Kanagawa" } ] } ] }
このページの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);
To use the MongoDB .NET/C# driver to add a $bucket stage to an aggregation pipeline, call the Unwind() method on a PipelineDefinition object.
次の例では、受信ドキュメントを Runtimeフィールドの値でグループ化するパイプラインステージを作成します。これは下限を含み、上限を含まない値です。
var pipeline = new EmptyPipelineDefinition<Movie>() .Bucket( groupBy: m => m.Runtime, boundaries: new List<int>() { 0, 71, 91, 121, 151, 201, 999 });
To customize the $bucket operation, pass an AggregateBucketOptions object to the Bucket() method. The following example performs the same $bucket operation as the previous example, but groups all documents with a Runtime value greater than 999 into the default bucket, named "Other":
var bucketOptions = new AggregateBucketOptions<BsonValue>() { DefaultBucket = (BsonValue)"Other" }; var pipeline = new EmptyPipelineDefinition<Movie>() .Bucket( groupBy: m => m.Runtime, boundaries: new List<BsonValue>() { 0, 71, 91, 121, 151, 201, 999 }, options: bucketOptions);
このページのNode.js の例では、Atlasサンプルデータセット の sample_mflixデータベースを使用します。無料のMongoDB Atlas cluster を作成し、サンプルデータセットをロードする方法については、 MongoDB Node.jsドライバーのドキュメントの開始を参照してください。
MongoDB Node.jsドライバーを使用して $bucket ステージを集計パイプラインに追加するには、パイプラインオブジェクトで $bucket 演算子を使用します。
次の例では、下限を含み上限を除いた runtime フィールドの値で受信するドキュメントをグループ化するパイプラインステージを作成します。集計ステージは、runtime の値が 999 を超えるすべてのドキュメントを "other" という名前のデフォルトのバケットにグループ化します。次に、この例は集計パイプラインを実行します。
const pipeline = [ { $bucket: { groupBy: "$runtime", boundaries: [0, 17, 91, 121, 151, 201, 999], default: "other" } } ]; const cursor = collection.aggregate(pipeline); return cursor;
詳細
関連するパイプラインステージの詳細については、$bucketAutoガイドを参照してください。