定義
バージョン 5.0 の新機能。
コレクション内の指定されたドキュメント範囲(ウィンドウと呼ばれる)に対して操作を実行し、選択したウィンドウ演算子 に基づいて結果を返します。
たとえば、$setWindowFields ステージを使用して以下を出力できます。
コレクション内の 2 つのドキュメント間の売上の差
売上ランキング
累計販売合計
データを外部データベースにエクスポートせずに、複雑な時系列情報の分析
構文
$setWindowFieldsステージ構文:
{ $setWindowFields: { partitionBy: <expression>, sortBy: { <sort field 1>: <sort order>, <sort field 2>: <sort order>, ..., <sort field n>: <sort order> }, output: { <output field 1>: { <window operator>: <window operator parameters>, window: { documents: [ <lower boundary>, <upper boundary> ], range: [ <lower boundary>, <upper boundary> ], unit: <time unit> } }, <output field 2>: { ... }, ... <output field n>: { ... } } } }
$setWindowFieldsステージは次のフィールドを持つドキュメントを取得します。
フィールド | 必要性 | 説明 |
|---|---|---|
任意 | ドキュメントをグループ化する式を指定します。 | |
一部の演算子に必要です(「制限事項」を参照してください) | パーティション内のドキュメントを並べ替えるフィールドを指定します。 | |
必須 |
フィールドにドットを含めて、埋め込みドキュメントフィールドと配列フィールドを指定できます。
| |
任意 | ||
任意 | コレクションから読み取られた現在のドキュメントの位置を基準にして下限と上限が指定されるウィンドウ。 ウィンドウの境界は、下限と上限の文字列または整数を含む 2 つの要素の配列を使用して指定されます。次を使用します。
| |
任意 | ||
任意 | 時間の範囲ウィンドウ境界の単位を指定します。次のいずれかの文字列に設定できます。
省略した場合は、デフォルトの数値範囲ウィンドウ境界が使用されます。 「時間の範囲ウィンドウの例」を参照してください。 |
Tip
動作
$setWindowFields ステージでは、既存のドキュメントに新しいフィールドが追加されます。集計操作には、1 つ以上の $setWindowFields ステージを含めることができます。
MongoDB 5.3 以降では、$setWindowFields ステージを トランザクションと "snapshot" 読み取り保証(read concern)とともに使用できます。
$setWindowFields ステージでは、返されるドキュメントの順序は保証されません。
ウィンドウオペレーター
これらの演算子は$setWindowFieldsステージで使用できます。
- Accumulator operators:
$addToSet,$avg,$bottom,$bottomN,$count,$covariancePop,$covarianceSamp,$derivative,$expMovingAvg,$firstN,$integral,$lastN,$max,$maxN,$median,$min,$minN,$percentile,$push,$stdDevSamp,$stdDevPop,$sum,$top,$topN.
- ギャップ補充演算子:
$linearFillおよび$locf。
制限事項
$setWindowFieldsステージの制限:
MongoDB 5.3 以前のバージョンでは、
$setWindowFieldsステージは使用できません。トランザクション内。
"snapshot"読み取り保証(read concern)内。
範囲ウィンドウの場合、指定された範囲内の数値のみがウィンドウに含まれます。欠落値、未定義値、および
null値は除外されます。時間範囲ウィンドウの場合。
ウィンドウには日付と時刻の種類のみが含まれます。
数値境界値は整数である必要があります。たとえば、境界として 2 時間を使用できますが、1.5 時間は使用できません。
例
カリフォルニア州(CA)とワシントン州(WA)のケーキ販売を含む cakeSales コレクションを作成します。
db.cakeSales.insertMany( [ { _id: 0, type: "chocolate", orderDate: new Date("2020-05-18T14:10:30Z"), state: "CA", price: 13, quantity: 120 }, { _id: 1, type: "chocolate", orderDate: new Date("2021-03-20T11:30:05Z"), state: "WA", price: 14, quantity: 140 }, { _id: 2, type: "vanilla", orderDate: new Date("2021-01-11T06:31:15Z"), state: "CA", price: 12, quantity: 145 }, { _id: 3, type: "vanilla", orderDate: new Date("2020-02-08T13:13:23Z"), state: "WA", price: 13, quantity: 104 }, { _id: 4, type: "strawberry", orderDate: new Date("2019-05-18T16:09:01Z"), state: "CA", price: 41, quantity: 162 }, { _id: 5, type: "strawberry", orderDate: new Date("2019-01-08T06:12:03Z"), state: "WA", price: 43, quantity: 134 } ] )
次の例では cakeSales コレクションを使用します。
ドキュメント ウィンドウの例
ドキュメント ウィンドウを使用して、各状態の累積数量を取得する
この例では、 $setWindowFieldsquantityのドキュメントウィンドウを使用して、各 の累計のケーキ売上state を出力します。出力例では、cumulativeQuantityForState quantityCAフィールドには、 と の累積WA が表示されます。
db.cakeSales.aggregate( [ { $setWindowFields: { partitionBy: "$state", sortBy: { orderDate: 1 }, output: { cumulativeQuantityForState: { $sum: "$quantity", window: { documents: [ "unbounded", "current" ] } } } } } ] )
[ { _id: 4, type: 'strawberry', orderDate: ISODate('2019-05-18T16:09:01.000Z'), state: 'CA', price: 41, quantity: 162, cumulativeQuantityForState: 162 }, { _id: 0, type: 'chocolate', orderDate: ISODate('2020-05-18T14:10:30.000Z'), state: 'CA', price: 13, quantity: 120, cumulativeQuantityForState: 282 }, { _id: 2, type: 'vanilla', orderDate: ISODate('2021-01-11T06:31:15.000Z'), state: 'CA', price: 12, quantity: 145, cumulativeQuantityForState: 427 }, { _id: 5, type: 'strawberry', orderDate: ISODate('2019-01-08T06:12:03.000Z'), state: 'WA', price: 43, quantity: 134, cumulativeQuantityForState: 134 }, { _id: 3, type: 'vanilla', orderDate: ISODate('2020-02-08T13:13:23.000Z'), state: 'WA', price: 13, quantity: 104, cumulativeQuantityForState: 238 }, { _id: 1, type: 'chocolate', orderDate: ISODate('2021-03-20T11:30:05.000Z'), state: 'WA', price: 14, quantity: 140, cumulativeQuantityForState: 378 } ]
この例では、次のことが行われます。
partitionBy: "$state"コレクション内のドキュメントをstateで分割します。CAとWA用のパーティションがあります。sortBy: { orderDate: 1 }は各パーティション内のドキュメントをorderDateで昇順(1)にソートするため、最も近いorderDateが先頭になります。
ドキュメント ウィンドウを使用して、各年の累積数量を取得する
この例では、 $setWindowFieldsquantity$yearorderDateのドキュメントウィンドウを使用して、 の各 の累計のケーキ売上 を出力します。出力の例では、cumulativeQuantityForYear quantityフィールドには各年の累積 が表示されます。
db.cakeSales.aggregate( [ { $setWindowFields: { partitionBy: { $year: "$orderDate" }, sortBy: { orderDate: 1 }, output: { cumulativeQuantityForYear: { $sum: "$quantity", window: { documents: [ "unbounded", "current" ] } } } } } ] )
[ { _id: 5, type: 'strawberry', orderDate: ISODate('2019-01-08T06:12:03.000Z'), state: 'WA', price: 43, quantity: 134, cumulativeQuantityForYear: 134 }, { _id: 4, type: 'strawberry', orderDate: ISODate('2019-05-18T16:09:01.000Z'), state: 'CA', price: 41, quantity: 162, cumulativeQuantityForYear: 296 }, { _id: 3, type: 'vanilla', orderDate: ISODate('2020-02-08T13:13:23.000Z'), state: 'WA', price: 13, quantity: 104, cumulativeQuantityForYear: 104 }, { _id: 0, type: 'chocolate', orderDate: ISODate('2020-05-18T14:10:30.000Z'), state: 'CA', price: 13, quantity: 120, cumulativeQuantityForYear: 224 }, { _id: 2, type: 'vanilla', orderDate: ISODate('2021-01-11T06:31:15.000Z'), state: 'CA', price: 12, quantity: 145, cumulativeQuantityForYear: 145 }, { _id: 1, type: 'chocolate', orderDate: ISODate('2021-03-20T11:30:05.000Z'), state: 'WA', price: 14, quantity: 140, cumulativeQuantityForYear: 285 } ]
この例では、次のことが行われます。
ドキュメントウィンドウを使用して各年の移動平均数量を取得する
この例では、 $setWindowFieldsのドキュメントウィンドウを使用して、ケーキの売上quantity の移動平均を出力します。出力の例では、averageQuantity フィールドに移動平均quantity が表示されます。
db.cakeSales.aggregate( [ { $setWindowFields: { partitionBy: { $year: "$orderDate" }, sortBy: { orderDate: 1 }, output: { averageQuantity: { $avg: "$quantity", window: { documents: [ -1, 0 ] } } } } } ] )
[ { _id: 5, type: 'strawberry', orderDate: ISODate('2019-01-08T06:12:03.000Z'), state: 'WA', price: 43, quantity: 134, averageQuantity: 134 }, { _id: 4, type: 'strawberry', orderDate: ISODate('2019-05-18T16:09:01.000Z'), state: 'CA', price: 41, quantity: 162, averageQuantity: 148 }, { _id: 3, type: 'vanilla', orderDate: ISODate('2020-02-08T13:13:23.000Z'), state: 'WA', price: 13, quantity: 104, averageQuantity: 104 }, { _id: 0, type: 'chocolate', orderDate: ISODate('2020-05-18T14:10:30.000Z'), state: 'CA', price: 13, quantity: 120, averageQuantity: 112 }, { _id: 2, type: 'vanilla', orderDate: ISODate('2021-01-11T06:31:15.000Z'), state: 'CA', price: 12, quantity: 145, averageQuantity: 145 }, { _id: 1, type: 'chocolate', orderDate: ISODate('2021-03-20T11:30:05.000Z'), state: 'WA', price: 14, quantity: 140, averageQuantity: 142.5 } ]
この例では、次のことが行われます。
ドキュメント ウィンドウを使用して各年の累計数量と最大数量を取得します
この例では、 $setWindowFieldsquantity$yearorderDateのドキュメントウィンドウを使用して、 の各 の累計と最大のケーキ売上 値を出力します。出力例では、cumulativeQuantityForYear フィールドには累積quantity が表示され、maximumQuantityForYear フィールドには最大のquantity が表示されます。
db.cakeSales.aggregate( [ { $setWindowFields: { partitionBy: { $year: "$orderDate" }, sortBy: { orderDate: 1 }, output: { cumulativeQuantityForYear: { $sum: "$quantity", window: { documents: [ "unbounded", "current" ] } }, maximumQuantityForYear: { $max: "$quantity", window: { documents: [ "unbounded", "unbounded" ] } } } } } ] )
[ { _id: 5, type: 'strawberry', orderDate: ISODate('2019-01-08T06:12:03.000Z'), state: 'WA', price: 43, quantity: 134, cumulativeQuantityForYear: 134, maximumQuantityForYear: 162 }, { _id: 4, type: 'strawberry', orderDate: ISODate('2019-05-18T16:09:01.000Z'), state: 'CA', price: 41, quantity: 162, cumulativeQuantityForYear: 296, maximumQuantityForYear: 162 }, { _id: 3, type: 'vanilla', orderDate: ISODate('2020-02-08T13:13:23.000Z'), state: 'WA', price: 13, quantity: 104, cumulativeQuantityForYear: 104, maximumQuantityForYear: 120 }, { _id: 0, type: 'chocolate', orderDate: ISODate('2020-05-18T14:10:30.000Z'), state: 'CA', price: 13, quantity: 120, cumulativeQuantityForYear: 224, maximumQuantityForYear: 120 }, { _id: 2, type: 'vanilla', orderDate: ISODate('2021-01-11T06:31:15.000Z'), state: 'CA', price: 12, quantity: 145, cumulativeQuantityForYear: 145, maximumQuantityForYear: 145 }, { _id: 1, type: 'chocolate', orderDate: ISODate('2021-03-20T11:30:05.000Z'), state: 'WA', price: 14, quantity: 140, cumulativeQuantityForYear: 285, maximumQuantityForYear: 145 } ]
この例では、次のことが行われます。
partitionBy: "$orderDate"コレクション内のドキュメントを$yearのorderDateで 分割 します。20192020、 、2021用のパーティションがあります。sortBy: { orderDate: 1 }は各パーティション内のドキュメントをorderDateで昇順(1)にソートするため、最も近いorderDateが先頭になります。output:cumulativeQuantityForYearフィールドを各年の累積quantityに設定します。maximumQuantityForYearフィールドを各年の最大値quantityに設定します。
範囲ウィンドウの例
この例では、 $setWindowFieldsquantity10の範囲ウィンドウを使用して、現在のドキュメントのprice 値のプラスマイナス ドル以内の注文で販売されたケーキの 値の合計を返します。出力例では、quantityFromSimilarOrders フィールドにはウィンドウ内のドキュメントのquantity 値の合計が表示されます。
db.cakeSales.aggregate( [ { $setWindowFields: { partitionBy: "$state", sortBy: { price: 1 }, output: { quantityFromSimilarOrders: { $sum: "$quantity", window: { range: [ -10, 10 ] } } } } } ] )
[ { _id: 2, type: 'vanilla', orderDate: ISODate('2021-01-11T06:31:15.000Z'), state: 'CA', price: 12, quantity: 145, quantityFromSimilarOrders: 265 }, { _id: 0, type: 'chocolate', orderDate: ISODate('2020-05-18T14:10:30.000Z'), state: 'CA', price: 13, quantity: 120, quantityFromSimilarOrders: 265 }, { _id: 4, type: 'strawberry', orderDate: ISODate('2019-05-18T16:09:01.000Z'), state: 'CA', price: 41, quantity: 162, quantityFromSimilarOrders: 162 }, { _id: 3, type: 'vanilla', orderDate: ISODate('2020-02-08T13:13:23.000Z'), state: 'WA', price: 13, quantity: 104, quantityFromSimilarOrders: 244 }, { _id: 1, type: 'chocolate', orderDate: ISODate('2021-03-20T11:30:05.000Z'), state: 'WA', price: 14, quantity: 140, quantityFromSimilarOrders: 244 }, { _id: 5, type: 'strawberry', orderDate: ISODate('2019-01-08T06:12:03.000Z'), state: 'WA', price: 43, quantity: 134, quantityFromSimilarOrders: 134 } ]
この例では、次のことが行われます。
時間範囲ウィンドウの例
上限が正の値である時間範囲ウィンドウを使用する
次の例では、 $setWindowFieldsorderDatestateの上限時間範囲単位が正のウィンドウを使用します。パイプラインは、指定された時間範囲に一致する各 の 値の配列を出力します。出力例では、recentOrders orderDateCAフィールドには、 と のWA 値の配列が表示されます。
db.cakeSales.aggregate( [ { $setWindowFields: { partitionBy: "$state", sortBy: { orderDate: 1 }, output: { recentOrders: { $push: "$orderDate", window: { range: [ "unbounded", 10 ], unit: "month" } } } } } ] )
[ { _id: 4, type: 'strawberry', orderDate: ISODate('2019-05-18T16:09:01.000Z'), state: 'CA', price: 41, quantity: 162, recentOrders: [ ISODate('2019-05-18T16:09:01.000Z') ] }, { _id: 0, type: 'chocolate', orderDate: ISODate('2020-05-18T14:10:30.000Z'), state: 'CA', price: 13, quantity: 120, recentOrders: [ ISODate('2019-05-18T16:09:01.000Z'), ISODate('2020-05-18T14:10:30.000Z'), ISODate('2021-01-11T06:31:15.000Z') ] }, { _id: 2, type: 'vanilla', orderDate: ISODate('2021-01-11T06:31:15.000Z'), state: 'CA', price: 12, quantity: 145, recentOrders: [ ISODate('2019-05-18T16:09:01.000Z'), ISODate('2020-05-18T14:10:30.000Z'), ISODate('2021-01-11T06:31:15.000Z') ] }, { _id: 5, type: 'strawberry', orderDate: ISODate('2019-01-08T06:12:03.000Z'), state: 'WA', price: 43, quantity: 134, recentOrders: [ ISODate('2019-01-08T06:12:03.000Z') ] }, { _id: 3, type: 'vanilla', orderDate: ISODate('2020-02-08T13:13:23.000Z'), state: 'WA', price: 13, quantity: 104, recentOrders: [ ISODate('2019-01-08T06:12:03.000Z'), ISODate('2020-02-08T13:13:23.000Z') ] }, { _id: 1, type: 'chocolate', orderDate: ISODate('2021-03-20T11:30:05.000Z'), state: 'WA', price: 14, quantity: 140, recentOrders: [ ISODate('2019-01-08T06:12:03.000Z'), ISODate('2020-02-08T13:13:23.000Z'), ISODate('2021-03-20T11:30:05.000Z') ] } ]
この例では、次のことが行われます。
partitionBy: "$state"コレクション内のドキュメントをstateで分割します。CAとWA用のパーティションがあります。sortBy: { orderDate: 1 }は各パーティション内のドキュメントをorderDateで昇順(1)にソートするため、最も近いorderDateが先頭になります。
$pushは、パーティションの先頭から、現在のドキュメントのorderDate値に10か月を加えた範囲に含まれるorderDate値を持つドキュメントまでの間のドキュメントのorderDate値の配列を返します。
負の上限を持つ時間範囲ウィンドウを使用する
次の例では、 $setWindowFieldsの負の上限時間範囲単位を持つウィンドウを使用します。パイプラインは、指定された時間範囲に一致する各orderDate のstate 値の配列を出力します。出力例では、recentOrders orderDateCAフィールドには、 と のWA 値の配列が表示されます。
db.cakeSales.aggregate( [ { $setWindowFields: { partitionBy: "$state", sortBy: { orderDate: 1 }, output: { recentOrders: { $push: "$orderDate", window: { range: [ "unbounded", -10 ], unit: "month" } } } } } ] )
[ { _id: 4, type: 'strawberry', orderDate: ISODate('2019-05-18T16:09:01.000Z'), state: 'CA', price: 41, quantity: 162, recentOrders: [] }, { _id: 0, type: 'chocolate', orderDate: ISODate('2020-05-18T14:10:30.000Z'), state: 'CA', price: 13, quantity: 120, recentOrders: [ ISODate('2019-05-18T16:09:01.000Z') ] }, { _id: 2, type: 'vanilla', orderDate: ISODate('2021-01-11T06:31:15.000Z'), state: 'CA', price: 12, quantity: 145, recentOrders: [ ISODate('2019-05-18T16:09:01.000Z') ] }, { _id: 5, type: 'strawberry', orderDate: ISODate('2019-01-08T06:12:03.000Z'), state: 'WA', price: 43, quantity: 134, recentOrders: [] }, { _id: 3, type: 'vanilla', orderDate: ISODate('2020-02-08T13:13:23.000Z'), state: 'WA', price: 13, quantity: 104, recentOrders: [ ISODate('2019-01-08T06:12:03.000Z') ] }, { _id: 1, type: 'chocolate', orderDate: ISODate('2021-03-20T11:30:05.000Z'), state: 'WA', price: 14, quantity: 140, recentOrders: [ ISODate('2019-01-08T06:12:03.000Z'), ISODate('2020-02-08T13:13:23.000Z') ] } ]
この例では、次のことが行われます。
partitionBy: "$state"コレクション内のドキュメントをstateで分割します。CAとWA用のパーティションがあります。sortBy: { orderDate: 1 }は各パーティション内のドキュメントをorderDateで昇順(1)にソートするため、最も近いorderDateが先頭になります。
$pushは、パーティションの先頭から、現在のドキュメントのorderDate値から10か月を引いた範囲に含まれるorderDate値を持つドキュメントまでの間のドキュメントのorderDate値の配列を返します。
次の WeatherMeasurementクラスは、気象測定値のコレクション内のドキュメントを表します。
[] public class WeatherMeasurement { [] public ObjectId Id { get; set; } [] public string LocalityId { get; set; } = null!; [] public DateTime MeasurementDateTime { get; set; } [] public float Rainfall { get; set; } [] public float Temperature { get; set; } }
MongoDB .NET/ C#ドライバーを使用して$setWindowFields ステージを集計パイプラインに追加するには、 PipelineDefinitionオブジェクトで UnionWith() メソッドを呼び出します。
次の例では、Rainfall フィールドと Temperature フィールドを使用して、各地域の過去 1 か月の累積降量、移動平均温度、中央値、90 パーセンタイル降量を計算するパイプラインステージを作成します。
var pipeline = new EmptyPipelineDefinition<WeatherMeasurement>() .SetWindowFields( partitionBy: w => w.LocalityId, sortBy: Builders<WeatherMeasurement>.Sort.Ascending( w => w.MeasurementDateTime), output: o => new { MonthlyRainfall = o.Sum( w => w.Rainfall, RangeWindow.Create( RangeWindow.Months(-1), RangeWindow.Current) ), TemperatureAvg = o.Average( w => w.Temperature, RangeWindow.Create( RangeWindow.Months(-1), RangeWindow.Current) ), MedianTemperature = o.Median( w => w.Temperature, RangeWindow.Create( RangeWindow.Months(-1), RangeWindow.Current) ), NinetiethPercentileRainfall = o.Percentile( w => w.Rainfall, new[] { 0.9 }, RangeWindow.Create( RangeWindow.Months(-1), RangeWindow.Current) ) } );
このページの Node.js の例では、Atlas サンプルデータセットの sample_weatherdata.data コレクションを使用します。無料の MongoDB Atlas クラスターを作成し、サンプルデータセットをロードする方法を学ぶには、MongoDB Node.js ドライバーのドキュメント「使用開始」をご覧ください。
MongoDB Node.jsドライバーを使用して $setWindowFields ステージを集計パイプラインに追加するには、パイプラインオブジェクトで $setWindowFields 演算子を使用します。
次の例では、過去1か月間におけるcallLettersの各一意の値に対して、平均airTemperature.valueと合計waveMeasurement.waves.heightを計算するパイプラインステージを作成します。次に、この例は集計パイプラインを実行します。
const pipeline = [ { $setWindowFields: { partitionBy: "$callLetters", sortBy: { ts: 1 }, output: { temperatureAvg: { $avg: "$airTemperature.value", window: { range: [-1, "current"], unit: "month" } }, totalWaveHeight: { $sum: "$waveMeasurement.waves.height", window: { range: [-1, "current"], unit: "month" } } } } }, ]; const cursor = collection.aggregate(pipeline); return cursor;
Tip
IoT 電力消費に関する追加の例については、電子書籍『 MongoDB の実用的な集計 』を参照してください。