文章目录
- MongoDB聚合运算符:$linearFill
- 语法
- 使用
- 对比`$fill`和`$linearFill`
- 举例
- 使用线性插值填充缺失值
- 在单个阶段中使用多种填充方法
MongoDB聚合运算符:$linearFill
$linearFill聚合运算符在一个窗口中基于附近字段的值使用线性插值填充null和缺失字段。
语法
{ $linearFill: <expression> }
使用
$linearFill聚合运算符在一个窗口中基于附近字段的非空值使用线性插值填充null和缺失字段。附近字段值由$setWindowFields的排序顺序决定。
-
$linearFill按比例填充空值和缺失值,跨越周围非空值之间的数值范围,要确定缺失字段的值,$linearFill使用:- 周围非空值的差值。
- 要填充周围值之间的空字段的数量。
-
$linearFill如果根据$setWindowFields中指定的排序顺序,前面和后面都有非空值,则可以填充多个连续的空值。
如果集合包含这些文档:{ index: 0, value: 0 }, { index: 1, value: null }, { index: 2, value: null }, { index: 3, value: null }, { index: 4, value: 10 }使用
$linearFill后为了填充空值,文档变成:{ index: 0, value: 0 }, { index: 1, value: 2.5 }, { index: 2, value: 5 }, { index: 3, value: 7.5 }, { index: 4, value: 10 } -
前后都没有非空值的
null仍为null。
注意:
- 要使用
$linearFill必须要使用sortBy字段对数据进行排序。 - 当使用线性填充窗口功能时,如果单个分区中的
sortBy字段中有任何重复值,$setWindowFields将返回错误。
对比$fill和$linearFill
使用$linearFill填充缺失字段值时,可以:
- 在
$fill阶段用{ method: "linear" }。当使用$fill阶段时,在输出中指定的字段与用作源数据的字段相同。 - 在
$setWindowFields中使用$linearFill操作符。可以为与用作源数据的字段不同的字段设置值。
举例
使用下面的脚本创建stock集合,包含了每小时跟踪的单个公司的股票价格信息:
db.stock.insertMany( [{time: ISODate("2021-03-08T09:00:00.000Z"),price: 500},{time: ISODate("2021-03-08T10:00:00.000Z"),},{time: ISODate("2021-03-08T11:00:00.000Z"),price: 515},{time: ISODate("2021-03-08T12:00:00.000Z")},{time: ISODate("2021-03-08T13:00:00.000Z")},{time: ISODate("2021-03-08T14:00:00.000Z"),price: 485}
] )
集合中的某些文档缺少price字段
使用线性插值填充缺失值
在$setWindowFields阶段内部,使用$linearFill线性插值填充缺失的price字段值:
db.stock.aggregate( [{$setWindowFields:{sortBy: { time: 1 },output:{price: { $linearFill: "$price" }}}}
] )
在本例中:
sortBy: { time: 1 }按time字段从最早到最晚的升序对文档进行排序。output指定了:price作为要填充的缺失值的字段{ $linearFill: "$price" }作为缺失字段的值。$linearFill基于序列中price周围的值使用线性插值来填充缺失的price的值。
输出结果:
[{_id: ObjectId("620ad555394d47411658b5ef"),time: ISODate("2021-03-08T09:00:00.000Z"),price: 500},{_id: ObjectId("620ad555394d47411658b5f0"),time: ISODate("2021-03-08T10:00:00.000Z"),price: 507.5},{_id: ObjectId("620ad555394d47411658b5f1"),time: ISODate("2021-03-08T11:00:00.000Z"),price: 515},{_id: ObjectId("620ad555394d47411658b5f2"),time: ISODate("2021-03-08T12:00:00.000Z"),price: 505},{_id: ObjectId("620ad555394d47411658b5f3"),time: ISODate("2021-03-08T13:00:00.000Z"),price: 495},{_id: ObjectId("620ad555394d47411658b5f4"),time: ISODate("2021-03-08T14:00:00.000Z"),price: 485}
]
在单个阶段中使用多种填充方法
当使用$setWindowFields阶段填充缺失值时,可以为与填充的字段不同的字段设置值,所以可以在单个$setWindowFields阶段中使用多个填充方法,并将结果输出到不同的字段中。
下面的聚合管道使用线性插值和最后观测前移法填充缺失的price字段的值:
db.stock.aggregate( [{$setWindowFields:{sortBy: { time: 1 },output:{linearFillPrice: { $linearFill: "$price" },locfPrice: { $locf: "$price" }}}}
] )
在本例中:
sortBy: { time: 1 }按time字段从最早到最晚的升序对文档进行排序。output指定了:linearFillPrice作为要填充的目标字段{ $linearFill: "$price" }是LinearFillPrice字段的值。$linearFill基于序列中price周围的值使用线性插值来填充缺失的price的值。
locfPrice作为要填充的目标字段{ $locf: "$price" }为locfPrice字段的值。locf代表最后一次观察结果。$locf使用序列中前一个文档中的值填充缺失的price的值。
结果输出:
[{_id: ObjectId("620ad555394d47411658b5ef"),time: ISODate("2021-03-08T09:00:00.000Z"),price: 500,linearFillPrice: 500,locfPrice: 500},{_id: ObjectId("620ad555394d47411658b5f0"),time: ISODate("2021-03-08T10:00:00.000Z"),linearFillPrice: 507.5,locfPrice: 500},{_id: ObjectId("620ad555394d47411658b5f1"),time: ISODate("2021-03-08T11:00:00.000Z"),price: 515,linearFillPrice: 515,locfPrice: 515},{_id: ObjectId("620ad555394d47411658b5f2"),time: ISODate("2021-03-08T12:00:00.000Z"),linearFillPrice: 505,locfPrice: 515},{_id: ObjectId("620ad555394d47411658b5f3"),time: ISODate("2021-03-08T13:00:00.000Z"),linearFillPrice: 495,locfPrice: 515},{_id: ObjectId("620ad555394d47411658b5f4"),time: ISODate("2021-03-08T14:00:00.000Z"),price: 485,linearFillPrice: 485,locfPrice: 485}
]