定义
版本 5.0 中的新增功能。
Performs operations on a specified span of documents in a collection, known as a window, and returns the results based on the chosen window operator.
For example, you can use the $setWindowFields stage to output the:
集合中两个文档之间的销售额差异。
销售排名。
累计销售总额。
分析复杂的时间序列信息,而无需将数据导出到外部数据库。
语法
The $setWindowFields stage syntax:
{ $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>: { ... } } } }
The $setWindowFields stage takes a document with these fields:
字段 | 必要性 | 说明 |
|---|---|---|
Optional | Specifies an expression to group the documents. In the | |
对于某些操作符是必需的(参见限制条件) | 指定分区中用于对文档进行排序的字段。使用与 | |
必需 | Specifies the field(s) to append to the documents in the output returned by the A field can contain dots to specify embedded document fields and array fields. The semantics for the embedded document dotted notation in the
| |
Optional | ||
Optional | 一个窗口,其中的上下界是相对于从集合中读取的当前文档的位置指定的。 窗口边界是使用包含下限和上限字符串或整数的双元素数组指定的。使用:
请参阅文档窗口示例。 | |
Optional | ||
Optional |
提示
行为
The $setWindowFields stage appends new fields to existing documents. You can include one or more $setWindowFields stages in an aggregation operation.
从MongoDB5.3 开始,您可以将$setWindowFields 阶段与事务和 "snapshot"读关注(read concern)一起使用。
$setWindowFields 阶段不保证返回文档的顺序。
窗口运算符
These operators can be used with the $setWindowFields stage:
- 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。
限制
Restrictions for the $setWindowFields stage:
在MongoDB5.3 之前,无法使用
$setWindowFields阶段:在事务内。
带有
"snapshot"读关注。
For range windows, only numbers in the specified range are included in the window. Missing, undefined, and
nullvalues are excluded.对于时间范围窗口:
窗口中只包含日期和时间类型。
数值边界值必须为整数。例如,您可以使用 2 小时作为边界,但不能使用 1.5 小时。
示例
创建cakeSales集合,其中包含加利福尼亚州 ( CA ) 和华盛顿州 ( WA ) 的蛋糕销售情况:
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 集合。
文档窗口示例
使用文档窗口获取每个州的累计数量。
This example uses a documents window in $setWindowFields to output the cumulative cake sales quantity for each state. In the example output, the cumulativeQuantityForState field shows the cumulative quantity for CA and 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"partitions the documents in the collection bystate. There are partitions forCAandWA.sortBy: { orderDate: 1 }sorts the documents in each partition byorderDatein ascending order (1), so the earliestorderDateis first.
output:将
cumulativeQuantityForState字段设置为每个state的累积quantity,该值是通过将分区内的前一个值累加而得到的。Calculates the cumulative
quantityusing the$sumoperator run in a documents window.The window contains documents between an
unboundedlower limit and thecurrentdocument. This means$sumreturns the cumulativequantityfor the documents between the beginning of the partition and the current document.
使用文档窗口获取每年的累计数量
This example uses a documents window in $setWindowFields to output the cumulative cake sales quantity for each $year in orderDate. In the example output, the cumulativeQuantityForYear field shows the cumulative quantity for each year.
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 } ]
在示例中:
partitionBy: { $year: "$orderDate" }partitions the documents in the collection by$yearinorderDate. There are partitions for2019,2020, and2021.sortBy: { orderDate: 1 }sorts the documents in each partition byorderDatein ascending order (1), so the earliestorderDateis first.output:将
cumulativeQuantityForYear字段设置为每年的累积quantity,这个值通过对分区中先前值的连续添加而增加。Calculates the cumulative
quantityusing the$sumoperator run in a documents window.The window contains documents between an
unboundedlower limit and thecurrentdocument. This means$sumreturns the cumulativequantityfor the documents between the beginning of the partition and the current document.
使用文档窗口获取每年的移动平均数量
This example uses a documents window in $setWindowFields to output the moving average for the cake sales quantity. In the example output, the averageQuantity field shows the moving average 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 } ]
在示例中:
partitionBy: "$orderDate"partitions the documents in the collection by$yearinorderDate. There are partitions for2019,2020, and2021.sortBy: { orderDate: 1 }sorts the documents in each partition byorderDatein ascending order (1), so the earliestorderDateis first.output:将
averageQuantity字段设置为每年的移动平均值quantity。
使用文档窗口获取每年的累计数量和最大数量
This example uses a documents window in $setWindowFields to output the cumulative and maximum cake sales quantity values for each $year in orderDate. In the example output, the cumulativeQuantityForYear field shows the cumulative quantity and the maximumQuantityForYear field shows the maximum 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"partitions the documents in the collection by$yearinorderDate. There are partitions for2019,2020, and2021.sortBy: { orderDate: 1 }sorts the documents in each partition byorderDatein ascending order (1), so the earliestorderDateis first.output:将
cumulativeQuantityForYear字段设置为每年的累积quantity。Calculates the cumulative
quantityusing the$sumoperator run in a documents window.The window contains documents between an
unboundedlower limit and thecurrentdocument. This means$sumreturns the cumulative quantity for the documents between the beginning of the partition and the current document.将
maximumQuantityForYear字段设置为每年的最高量 (quantity)。
范围窗口示例
此示例使用$setWindowFields 中的范围窗口,返回当前文档 price 值正负 10 美元内的订单所售蛋糕的 quantity 值的总和。在示例输出中,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 } ]
在示例中:
partitionBy: "$state"partitions the documents in the collection bystate. There are partitions forCAandWA.sortBy: { price: 1 }sorts the documents in each partition bypricein ascending order (1), so the lowestpriceis first.
时间范围窗口示例
使用具有正上界的时间范围窗口
The following example uses a window with a positive upper bound time range unit in $setWindowFields. The pipeline outputs an array of orderDate values for each state that match the specified time range. In the example output, the recentOrders field shows the array of orderDate values for CA and 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"partitions the documents in the collection bystate. There are partitions forCAandWA.sortBy: { orderDate: 1 }sorts the documents in each partition byorderDatein ascending order (1), so the earliestorderDateis first.
该窗口包含介于下限
unbounded和上限设立为10(当前文档的10orderDate值后 个月)之间的文档,使用时间范围单位。$push返回分区起始和满足如下条件的文档之间文档的orderDate值的数组:orderDate值在当前文档的orderDate值(含)加上1010 个月范围内。
使用具有负上界的时间范围窗口
The following example uses a window with a negative upper bound time range unit in $setWindowFields. The pipeline outputs an array of orderDate values for each state that match the specified time range. In the example output, the recentOrders field shows the array of orderDate values for CA and 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"partitions the documents in the collection bystate. There are partitions forCAandWA.sortBy: { orderDate: 1 }sorts the documents in each partition byorderDatein ascending order (1), so the earliestorderDateis first.
该窗口包含介于下限
unbounded和上限设立为-10(当前文档的10orderDate值之前 个月)之间的文档(使用时间范围单位)。$push返回分区起始和满足如下条件的文档之间文档的orderDate值的数组:orderDate值在当前文档的orderDate值(含)减去1010 个月范围内。
以下 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; } }
To use the MongoDB .NET/C# driver to add a $setWindowFields stage to an aggregation pipeline, call the UnionWith() method on a PipelineDefinition object.
以下示例创建了一个管道阶段,该阶段使用 Rainfall 和 Temperature 字段计算每个地区过去一个月的累计降雨量、移动平均温度、中位数温度和 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操作符。
以下示例创建了一个管道阶段,该阶段计算过去一个月内 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;
提示
有关物联网功耗的其他示例,请参阅实用 MongoDB 聚合电子书。