$setWindowFields(集計)
定義
バージョン 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 つの要素の配列を使用して指定されます。次を使用します。
| |
任意 | 現在のドキュメントの sortByフィールドに基づく値の範囲を使用して下限と上限が定義されるウィンドウ。 ウィンドウの境界は、下限と上限の文字列または数値を含む 2 つの要素の配列を使用して指定されます。次を使用します。
| |
任意 |
動作
$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
。
ランク演算子:
$denseRank
、$documentNumber
、および$rank
。
制限事項
$setWindowFields
ステージの制限:
MongoDB 5.3 以前のバージョンでは、
$setWindowFields
ステージは使用できません。トランザクション内。
"snapshot"
読み取り保証(read concern)内。
sortBy は次の場合に必要です。
$linearFill
演算子。
範囲ウィンドウと時間範囲ウィンドウには sortBy フィールドを 1 つだけ含めることができ、並べ替えは昇順でなければなりません。
これらの演算子は暗黙的なウィンドウを使用し、ウィンドウオプションを指定するとエラーを返します。
範囲ウィンドウの場合、指定された範囲内の数値のみがウィンドウに含まれます。欠落値、未定義値、および
null
値は除外されます。時間範囲ウィンドウの場合。
ウィンドウには日付と時刻の種類のみが含まれます。
数値境界値は整数である必要があります。たとえば、境界として 2 時間を使用できますが、1.5 時間は使用できません。
空のウィンドウまたは互換性のない値を持つウィンドウ(例: 文字列で
$sum
を使用)の場合、返される値は演算子によって異なります。
例
カリフォルニア州(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
コレクションを使用します。
ドキュメント ウィンドウの例
ドキュメント ウィンドウを使用して、各状態の累積数量を取得する
この例では、$setWindowFields
の ドキュメント ウィンドウを使用して、各 state
の累計のケーキ売上 quantity
を出力します。
db.cakeSales.aggregate( [ { $setWindowFields: { partitionBy: "$state", sortBy: { orderDate: 1 }, output: { cumulativeQuantityForState: { $sum: "$quantity", window: { documents: [ "unbounded", "current" ] } } } } } ] )
この例では、次のことが行われます。
partitionBy: "$state"
コレクション内のドキュメントをstate
で分割します。CA
とWA
用のパーティションがあります。sortBy: { orderDate: 1 }
は各パーティション内のドキュメントをorderDate
で昇順(1
)にソートするため、最も近いorderDate
が先頭になります。
output
:
この出力例では、CA
と WA
の累積 quantity
が cumulativeQuantityForState
フィールドに表示されます。
{ "_id" : 4, "type" : "strawberry", "orderDate" : ISODate("2019-05-18T16:09:01Z"), "state" : "CA", "price" : 41, "quantity" : 162, "cumulativeQuantityForState" : 162 } { "_id" : 0, "type" : "chocolate", "orderDate" : ISODate("2020-05-18T14:10:30Z"), "state" : "CA", "price" : 13, "quantity" : 120, "cumulativeQuantityForState" : 282 } { "_id" : 2, "type" : "vanilla", "orderDate" : ISODate("2021-01-11T06:31:15Z"), "state" : "CA", "price" : 12, "quantity" : 145, "cumulativeQuantityForState" : 427 } { "_id" : 5, "type" : "strawberry", "orderDate" : ISODate("2019-01-08T06:12:03Z"), "state" : "WA", "price" : 43, "quantity" : 134, "cumulativeQuantityForState" : 134 } { "_id" : 3, "type" : "vanilla", "orderDate" : ISODate("2020-02-08T13:13:23Z"), "state" : "WA", "price" : 13, "quantity" : 104, "cumulativeQuantityForState" : 238 } { "_id" : 1, "type" : "chocolate", "orderDate" : ISODate("2021-03-20T11:30:05Z"), "state" : "WA", "price" : 14, "quantity" : 140, "cumulativeQuantityForState" : 378 }
ドキュメント ウィンドウを使用して、各年の累積数量を取得する
この例では、 $setWindowFields
quantity
の ドキュメント$year
ウィンドウを使用して、 の各 の累計のケーキ売上orderDate
を出力します。
db.cakeSales.aggregate( [ { $setWindowFields: { partitionBy: { $year: "$orderDate" }, sortBy: { orderDate: 1 }, output: { cumulativeQuantityForYear: { $sum: "$quantity", window: { documents: [ "unbounded", "current" ] } } } } } ] )
この例では、次のことが行われます。
partitionBy: { $year: "$orderDate" }
コレクション内のドキュメントをorderDate
の$year
で分割します。2019
、2020
、および2021
のパーティションがあります。sortBy: { orderDate: 1 }
は各パーティション内のドキュメントをorderDate
で昇順(1
)にソートするため、最も近いorderDate
が先頭になります。output
:
この出力例では、各年の累積 quantity
が cumulativeQuantityForYear
フィールドに表示されます。
{ "_id" : 5, "type" : "strawberry", "orderDate" : ISODate("2019-01-08T06:12:03Z"), "state" : "WA", "price" : 43, "quantity" : 134, "cumulativeQuantityForYear" : 134 } { "_id" : 4, "type" : "strawberry", "orderDate" : ISODate("2019-05-18T16:09:01Z"), "state" : "CA", "price" : 41, "quantity" : 162, "cumulativeQuantityForYear" : 296 } { "_id" : 3, "type" : "vanilla", "orderDate" : ISODate("2020-02-08T13:13:23Z"), "state" : "WA", "price" : 13, "quantity" : 104, "cumulativeQuantityForYear" : 104 } { "_id" : 0, "type" : "chocolate", "orderDate" : ISODate("2020-05-18T14:10:30Z"), "state" : "CA", "price" : 13, "quantity" : 120, "cumulativeQuantityForYear" : 224 } { "_id" : 2, "type" : "vanilla", "orderDate" : ISODate("2021-01-11T06:31:15Z"), "state" : "CA", "price" : 12, "quantity" : 145, "cumulativeQuantityForYear" : 145 } { "_id" : 1, "type" : "chocolate", "orderDate" : ISODate("2021-03-20T11:30:05Z"), "state" : "WA", "price" : 14, "quantity" : 140, "cumulativeQuantityForYear" : 285 }
ドキュメントウィンドウを使用して各年の移動平均数量を取得する
この例では、 $setWindowFields
quantity
の ドキュメント ウィンドウを使用して、ケーキの売上 の移動平均を出力します。
db.cakeSales.aggregate( [ { $setWindowFields: { partitionBy: { $year: "$orderDate" }, sortBy: { orderDate: 1 }, output: { averageQuantity: { $avg: "$quantity", window: { documents: [ -1, 0 ] } } } } } ] )
この例では、次のことが行われます。
partitionBy: "$orderDate"
コレクション内のドキュメントをorderDate
の$year
で分割します。2019
、2020
、および2021
のパーティションがあります。sortBy: { orderDate: 1 }
は各パーティション内のドキュメントをorderDate
で昇順(1
)にソートするため、最も近いorderDate
が先頭になります。output
:
この出力例では、移動平均 quantity
が averageQuantity
フィールドに表示されます。
{ "_id" : 5, "type" : "strawberry", "orderDate" : ISODate("2019-01-08T06:12:03Z"), "state" : "WA", "price" : 43, "quantity" : 134, "averageQuantity" : 134 } { "_id" : 4, "type" : "strawberry", "orderDate" : ISODate("2019-05-18T16:09:01Z"), "state" : "CA", "price" : 41, "quantity" : 162, "averageQuantity" : 148 } { "_id" : 3, "type" : "vanilla", "orderDate" : ISODate("2020-02-08T13:13:23Z"), "state" : "WA", "price" : 13, "quantity" : 104, "averageQuantity" : 104 } { "_id" : 0, "type" : "chocolate", "orderDate" : ISODate("2020-05-18T14:10:30Z"), "state" : "CA", "price" : 13, "quantity" : 120, "averageQuantity" : 112 } { "_id" : 2, "type" : "vanilla", "orderDate" : ISODate("2021-01-11T06:31:15Z"), "state" : "CA", "price" : 12, "quantity" : 145, "averageQuantity" : 145 } { "_id" : 1, "type" : "chocolate", "orderDate" : ISODate("2021-03-20T11:30:05Z"), "state" : "WA", "price" : 14, "quantity" : 140, "averageQuantity" : 142.5 }
ドキュメント ウィンドウを使用して各年の累計数量と最大数量を取得します
この例では、 $setWindowFields
quantity
の ドキュメント$year
ウィンドウを使用して、 の各 の累計と最大のケーキ販売 値を出力します。orderDate
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" ] } } } } } ] )
この例では、次のことが行われます。
partitionBy: "$orderDate"
コレクション内のドキュメントをorderDate
の$year
で分割します。2019
、2020
、および2021
のパーティションがあります。sortBy: { orderDate: 1 }
は各パーティション内のドキュメントをorderDate
で昇順(1
)にソートするため、最も近いorderDate
が先頭になります。output
:cumulativeQuantityForYear
フィールドを各年の累積quantity
に設定します。ドキュメント ウィンドウで実行される
$sum
演算子を使用して累積quantity
を計算します。ウィンドウには、
unbounded
下限とcurrent
ドキュメントの間のドキュメントが含まれています。つまり、$sum
は、パーティションの最初から現在のドキュメントまで、ドキュメントの累積数量を返します。maximumQuantityForYear
フィールドを各年の最大値quantity
に設定します。ドキュメント ウィンドウで実行される
$max
演算子を使用して、すべてのドキュメントの最大値quantity
を計算します。ウィンドウには、
unbounded
の下限から上限 (upper
) の間のドキュメントが含まれています。つまり、$max
はパーティション内のドキュメントの最大量を返します。
この出力例では、累積 quantity
が cumulativeQuantityForYear
フィールドに表示され、最大値 quantity
が maximumQuantityForYear
フィールドに表示されます。
{ "_id" : 5, "type" : "strawberry", "orderDate" : ISODate("2019-01-08T06:12:03Z"), "state" : "WA", "price" : 43, "quantity" : 134, "cumulativeQuantityForYear" : 134, "maximumQuantityForYear" : 162 } { "_id" : 4, "type" : "strawberry", "orderDate" : ISODate("2019-05-18T16:09:01Z"), "state" : "CA", "price" : 41, "quantity" : 162, "cumulativeQuantityForYear" : 296, "maximumQuantityForYear" : 162 } { "_id" : 3, "type" : "vanilla", "orderDate" : ISODate("2020-02-08T13:13:23Z"), "state" : "WA", "price" : 13, "quantity" : 104, "cumulativeQuantityForYear" : 104, "maximumQuantityForYear" : 120 } { "_id" : 0, "type" : "chocolate", "orderDate" : ISODate("2020-05-18T14:10:30Z"), "state" : "CA", "price" : 13, "quantity" : 120, "cumulativeQuantityForYear" : 224, "maximumQuantityForYear" : 120 } { "_id" : 2, "type" : "vanilla", "orderDate" : ISODate("2021-01-11T06:31:15Z"), "state" : "CA", "price" : 12, "quantity" : 145, "cumulativeQuantityForYear" : 145, "maximumQuantityForYear" : 145 } { "_id" : 1, "type" : "chocolate", "orderDate" : ISODate("2021-03-20T11:30:05Z"), "state" : "WA", "price" : 14, "quantity" : 140, "cumulativeQuantityForYear" : 285, "maximumQuantityForYear" : 145 }
範囲ウィンドウの例
この例では、範囲ウィンドウを $setWindowFields
で使用して、現在のドキュメントの price
値のプラスマイナス 10 ドル以内の注文で販売されたケーキの quantity
値の合計を返します。
db.cakeSales.aggregate( [ { $setWindowFields: { partitionBy: "$state", sortBy: { price: 1 }, output: { quantityFromSimilarOrders: { $sum: "$quantity", window: { range: [ -10, 10 ] } } } } } ] )
この例では、次のことが行われます。
partitionBy: "$state"
コレクション内のドキュメントをstate
で分割します。CA
とWA
用のパーティションがあります。sortBy: { price: 1 }
は各パーティション内のドキュメントをprice
で昇順(1
)にソートするため、最低のprice
が先頭になります。output
quantityFromSimilarOrders
フィールドを、範囲 ウィンドウ内のドキュメントのquantity
値の合計に設定します。
この出力例では、ウィンドウ内のドキュメントの quantity
値の合計が quantityFromSimilarOrders
フィールドに表示されます。
{ "_id" : 2, "type" : "vanilla", "orderDate" : ISODate("2021-01-11T06:31:15Z"), "state" : "CA", "price" : 12, "quantity" : 145, "quantityFromSimilarOrders" : 265 } { "_id" : 0, "type" : "chocolate", "orderDate" : ISODate("2020-05-18T14:10:30Z"), "state" : "CA", "price" : 13, "quantity" : 120, "quantityFromSimilarOrders" : 265 } { "_id" : 4, "type" : "strawberry", "orderDate" : ISODate("2019-05-18T16:09:01Z"), "state" : "CA", "price" : 41, "quantity" : 162, "quantityFromSimilarOrders" : 162 } { "_id" : 3, "type" : "vanilla", "orderDate" : ISODate("2020-02-08T13:13:23Z"), "state" : "WA", "price" : 13, "quantity" : 104, "quantityFromSimilarOrders" : 244 } { "_id" : 1, "type" : "chocolate", "orderDate" : ISODate("2021-03-20T11:30:05Z"), "state" : "WA", "price" : 14, "quantity" : 140, "quantityFromSimilarOrders" : 244 } { "_id" : 5, "type" : "strawberry", "orderDate" : ISODate("2019-01-08T06:12:03Z"), "state" : "WA", "price" : 43, "quantity" : 134, "quantityFromSimilarOrders" : 134 }
時間範囲ウィンドウの例
上限が正の値である時間範囲ウィンドウを使用する
次の例では、 の正の上限時間範囲 単位 を持つ$setWindowFields
ウィンドウ を使用します。パイプラインは、指定された時間範囲に一致する各state
のorderDate
値の配列を出力します。
db.cakeSales.aggregate( [ { $setWindowFields: { partitionBy: "$state", sortBy: { orderDate: 1 }, output: { recentOrders: { $push: "$orderDate", window: { range: [ "unbounded", 10 ], unit: "month" } } } } } ] )
この例では、次のことが行われます。
partitionBy: "$state"
コレクション内のドキュメントをstate
で分割します。CA
とWA
用のパーティションがあります。sortBy: { orderDate: 1 }
は各パーティション内のドキュメントをorderDate
で昇順(1
)にソートするため、最も近いorderDate
が先頭になります。output
:
ウィンドウには、時間範囲 単位を使用して、下限値
unbounded
と上限値10
(現在のドキュメントのorderDate
値から 10 か月後)の間のドキュメントが含まれます。$push
は、パーティションの先頭から、現在のドキュメントのorderDate
値に10
か月を加えた範囲に含まれるorderDate
値を持つドキュメントまでの間のドキュメントのorderDate
値の配列を返します。
この出力例では、CA
と WA
の orderDate
値の配列が recentOrders
フィールドに表示されます。
{ "_id" : 4, "type" : "strawberry", "orderDate" : ISODate("2019-05-18T16:09:01Z"), "state" : "CA", "price" : 41, "quantity" : 162, "recentOrders" : [ ISODate("2019-05-18T16:09:01Z") ] } { "_id" : 0, "type" : "chocolate", "orderDate" : ISODate("2020-05-18T14:10:30Z"), "state" : "CA", "price" : 13, "quantity" : 120, "recentOrders" : [ ISODate("2019-05-18T16:09:01Z"), ISODate("2020-05-18T14:10:30Z"), ISODate("2021-01-11T06:31:15Z") ] } { "_id" : 2, "type" : "vanilla", "orderDate" : ISODate("2021-01-11T06:31:15Z"), "state" : "CA", "price" : 12, "quantity" : 145, "recentOrders" : [ ISODate("2019-05-18T16:09:01Z"), ISODate("2020-05-18T14:10:30Z"), ISODate("2021-01-11T06:31:15Z") ] } { "_id" : 5, "type" : "strawberry", "orderDate" : ISODate("2019-01-08T06:12:03Z"), "state" : "WA", "price" : 43, "quantity" : 134, "recentOrders" : [ ISODate("2019-01-08T06:12:03Z") ] } { "_id" : 3, "type" : "vanilla", "orderDate" : ISODate("2020-02-08T13:13:23Z"), "state" : "WA", "price" : 13, "quantity" : 104, "recentOrders" : [ ISODate("2019-01-08T06:12:03Z"), ISODate("2020-02-08T13:13:23Z") ] } { "_id" : 1, "type" : "chocolate", "orderDate" : ISODate("2021-03-20T11:30:05Z"), "state" : "WA", "price" : 14, "quantity" : 140, "recentOrders" : [ ISODate("2019-01-08T06:12:03Z"), ISODate("2020-02-08T13:13:23Z"), ISODate("2021-03-20T11:30:05Z") ] }
負の上限を持つ時間範囲ウィンドウを使用する
次の例では、 の負の上限時間範囲 単位 $setWindowFields
を持つ ウィンドウ を使用します。パイプラインは、指定された時間範囲に一致する各state
のorderDate
値の配列を出力します。
db.cakeSales.aggregate( [ { $setWindowFields: { partitionBy: "$state", sortBy: { orderDate: 1 }, output: { recentOrders: { $push: "$orderDate", window: { range: [ "unbounded", -10 ], unit: "month" } } } } } ] )
この例では、次のことが行われます。
partitionBy: "$state"
コレクション内のドキュメントをstate
で分割します。CA
とWA
用のパーティションがあります。sortBy: { orderDate: 1 }
は各パーティション内のドキュメントをorderDate
で昇順(1
)にソートするため、最も近いorderDate
が先頭になります。output
:
ウィンドウには、時間範囲単位を使用して、
unbounded
下限と-10
(現在のドキュメントのorderDate
値より10か月前)の間のドキュメントが含まれます。$push
は、パーティションの先頭から、現在のドキュメントのorderDate
値から10
か月を引いた範囲に含まれるorderDate
値を持つドキュメントまでの間のドキュメントのorderDate
値の配列を返します。
この出力例では、CA
と WA
の orderDate
値の配列が recentOrders
フィールドに表示されます。
{ "_id" : 4, "type" : "strawberry", "orderDate" : ISODate("2019-05-18T16:09:01Z"), "state" : "CA", "price" : 41, "quantity" : 162, "recentOrders" : [ ] } { "_id" : 0, "type" : "chocolate", "orderDate" : ISODate("2020-05-18T14:10:30Z"), "state" : "CA", "price" : 13, "quantity" : 120, "recentOrders" : [ ISODate("2019-05-18T16:09:01Z") ] } { "_id" : 2, "type" : "vanilla", "orderDate" : ISODate("2021-01-11T06:31:15Z"), "state" : "CA", "price" : 12, "quantity" : 145, "recentOrders" : [ ISODate("2019-05-18T16:09:01Z") ] } { "_id" : 5, "type" : "strawberry", "orderDate" : ISODate("2019-01-08T06:12:03Z"), "state" : "WA", "price" : 43, "quantity" : 134, "recentOrders" : [ ] } { "_id" : 3, "type" : "vanilla", "orderDate" : ISODate("2020-02-08T13:13:23Z"), "state" : "WA", "price" : 13, "quantity" : 104, "recentOrders" : [ ISODate("2019-01-08T06:12:03Z") ] } { "_id" : 1, "type" : "chocolate", "orderDate" : ISODate("2021-03-20T11:30:05Z"), "state" : "WA", "price" : 14, "quantity" : 140, "recentOrders" : [ ISODate("2019-01-08T06:12:03Z"), ISODate("2020-02-08T13:13:23Z") ] }