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
}
]