$densify
阶段可以为文档序列中字段缺失的某些值创建新文档。其主要的用途有:
- 补齐时间序列数据。
- 为分组数据添加缺失值。
- 为指定的值范围填充数据。
语法
$densify
阶段的语法:
{
$densify: {
field: <fieldName>,
partitionByFields: [ <field 1>, <field 2> ... <field n> ],
range: {
step: <number>,
unit: <time unit>,
bounds: < "full" || "partition" > || [ < lower bound >, < upper bound > ]
}
}
}
$densify
阶段的参数主要有以下字段:
field
必选字段,要填充的字段,字段的值必须是数值或日期类型,文档中其他没有被field
指定的字段则会直接通过管道,不会被修改。如果指定的<field>
在内嵌文档或数组中,需要使用点号。
partitionByFields
可选字段,一组字段构成的键值用于对文档进行分组。在$densify
阶段,每组文档被称为一个分区。若省略这个字段,$densify
则对整个集合使用一个分组。
range
必选字段,一个对象,指定数据如何被填充。
range.bounds
必选字段,可以用下面两种方式指定range.bounds
:
- 数组形式:
[ < lower bound >, < upper bound > ],
- 字符串形式:
"full"
或"partition"
如果bounds
是一个数组:
-
$densify
添加涵盖指定范围值的文档。 -
bounds
的数据类型必须与填充的字段类型保持一致。
如果bounds
为"full"
:
-
$densify
添加涵盖指定范围值的文档。
如果bounds
为"partition"
:
-
$densify
将文档添加到每个分区,类似于单独对每个分区单独运行full
范围致密化。
range.step
必须字段,所有文档中field
值的增量,$densify
按照step(步长)
在已经存在的文档之间创建新文档。如果指定了range.unit
字段,step
必须是一个整数,否则step
可以是任意的数值。
range.unit
如果field
为日期则是必须字段,unit
用于日期类型的field
增量的单位。可以指定为下面字符串的值之一:
- millisecond
- second
- minute
- hour
- day
- week
- month
- quarter
- year
使用
field的限制
如果文档包含的field
有下列情况将报错:
- 集合中任何文档中指定的
field
值有日期类型,且没有指定unit
字段的 - 集合中任何文档中指定的
field
值有数值类型,且没有指定unit
字段的 - 如果要
densify
的字段field
名称以$
开头,必须要对其改名,可以使用$project
partitionByFields的限制
下面的情况出现在partitionByFields
数组字段名中时将报错:
- 求值结果为非字符串值
- 以
$
开头
range.bounds的行为
如果range.bounds
是一个数组:
- 下限值表示新增文档的起始值,与集合中已有的文档无关。
- 下限包含在内。
- 上限不包含在内。
-
$densify
不会过滤掉字段值超出指定范围的文档。
输出顺序
$densify
不保证输出文档的顺序。想要保证有序,可以使用$sort
对想要排序的字段进行排序。
举例
填充时间序列数据
创建一个包含四小时温度读数的weather
集合。
db.weather.insertMany( [
{
"metadata": { "sensorId": 5578, "type": "temperature" },
"timestamp": ISODate("2021-05-18T00:00:00.000Z"),
"temp": 12
},
{
"metadata": { "sensorId": 5578, "type": "temperature" },
"timestamp": ISODate("2021-05-18T04:00:00.000Z"),
"temp": 11
},
{
"metadata": { "sensorId": 5578, "type": "temperature" },
"timestamp": ISODate("2021-05-18T08:00:00.000Z"),
"temp": 11
},
{
"metadata": { "sensorId": 5578, "type": "temperature" },
"timestamp": ISODate("2021-05-18T12:00:00.000Z"),
"temp": 12
}
] )
下面使用$densify
阶段来填补四小时间隔之间的空白,实现小时粒度的数据点:
db.weather.aggregate( [
{
$densify: {
field: "timestamp",
range: {
step: 1,
unit: "hour",
bounds:[ ISODate("2021-05-18T00:00:00.000Z"), ISODate("2021-05-18T08:00:00.000Z") ]
}
}
}
] )
在这个例子中:
-
$densify
阶段填充温度记录之前的空缺时间-
field
:"timestamp"
填充timestamp(时间戳)
字段 -
range
:-
step:1
表示timestamp
字段的增量为1个单位 -
unit:hour
表示timestamp
字段填充为小时 -
bounds: [ ISODate("2021-05-18T00:00:00.000Z"), ISODate("2021-05-18T08:00:00.000Z") ]
设置了要填充的时间范围
-
-
在下面的输出中,$densify
阶段以小时为单位填充了00:00:00
到08:00:00
之间的间隙:
[
{
_id: ObjectId("618c207c63056cfad0ca4309"),
metadata: { sensorId: 5578, type: 'temperature' },
timestamp: ISODate("2021-05-18T00:00:00.000Z"),
temp: 12
},
{ timestamp: ISODate("2021-05-18T01:00:00.000Z") },
{ timestamp: ISODate("2021-05-18T02:00:00.000Z") },
{ timestamp: ISODate("2021-05-18T03:00:00.000Z") },
{
_id: ObjectId("618c207c63056cfad0ca430a"),
metadata: { sensorId: 5578, type: 'temperature' },
timestamp: ISODate("2021-05-18T04:00:00.000Z"),
temp: 11
},
{ timestamp: ISODate("2021-05-18T05:00:00.000Z") },
{ timestamp: ISODate("2021-05-18T06:00:00.000Z") },
{ timestamp: ISODate("2021-05-18T07:00:00.000Z") },
{
_id: ObjectId("618c207c63056cfad0ca430b"),
metadata: { sensorId: 5578, type: 'temperature' },
timestamp: ISODate("2021-05-18T08:00:00.000Z"),
temp: 11
}
{
_id: ObjectId("618c207c63056cfad0ca430c"),
metadata: { sensorId: 5578, type: 'temperature' },
timestamp: ISODate("2021-05-18T12:00:00.000Z"),
temp: 12
}
]
分区填充
创建一个coffee
数据集,其中包含两种咖啡豆的数据:
db.coffee.insertMany( [
{
"altitude": 600,
"variety": "Arabica Typica",
"score": 68.3
},
{
"altitude": 750,
"variety": "Arabica Typica",
"score": 69.5
},
{
"altitude": 950,
"variety": "Arabica Typica",
"score": 70.5
},
{
"altitude": 1250,
"variety": "Gesha",
"score": 88.15
},
{
"altitude": 1700,
"variety": "Gesha",
"score": 95.5,
"price": 1029
}
] )
填充范围内全部的值
下面的例子使用$densify
为所有的咖啡variety
填充altitude
字段:
db.coffee.aggregate( [
{
$densify: {
field: "altitude",
partitionByFields: [ "variety" ],
range: {
bounds: "full",
step: 200
}
}
}
] )
在上例的聚合中:
- 根据
variety
对文档进行分区,创建了两个分组分别是’Arabica Typica’和Gesha
咖啡。 - 指定了
full
范围,即在每个分区的现有文档范围内对数据进行填充。 - 指定了
200
的step
,即被创建的新文档的altitude
间隔为200
。
聚合输出下面的文档:文章来源地址https://www.toymoban.com/news/detail-828248.html
[
{
_id: ObjectId("618c031814fbe03334480475"),
altitude: 600,
variety: 'Arabica Typica',
score: 68.3
},
{
_id: ObjectId("618c031814fbe03334480476"),
altitude: 750,
variety: 'Arabica Typica',
score: 69.5
},
{ variety: 'Arabica Typica', altitude: 800 },
{
_id: ObjectId("618c031814fbe03334480477"),
altitude: 950,
variety: 'Arabica Typica',
score: 70.5
},
{ variety: 'Gesha', altitude: 600 },
{ variety: 'Gesha', altitude: 800 },
{ variety: 'Gesha', altitude: 1000 },
{ variety: 'Gesha', altitude: 1200 },
{
_id: ObjectId("618c031814fbe03334480478"),
altitude: 1250,
variety: 'Gesha',
score: 88.15
},
{ variety: 'Gesha', altitude: 1400 },
{ variety: 'Gesha', altitude: 1600 },
{
_id: ObjectId("618c031814fbe03334480479"),
altitude: 1700,
variety: 'Gesha',
score: 95.5,
price: 1029
},
{ variety: 'Arabica Typica', altitude: 1000 },
{ variety: 'Arabica Typica', altitude: 1200 },
{ variety: 'Arabica Typica', altitude: 1400 },
{ variety: 'Arabica Typica', altitude: 1600 }
]
在所有分区填充值
下面使用$densify
只对每个variety
中altitude
字段的间隙进行填充:
db.coffee.aggregate( [
{
$densify: {
field: "altitude",
partitionByFields: [ "variety" ],
range: {
bounds: "partition",
step: 200
}
}
}
] )
这个例子中的聚合:文章来源:https://www.toymoban.com/news/detail-828248.html
- 根据
variety
对文档进行分区,创建了两个分组分别是’Arabica Typica’和Gesha
咖啡。 - 指定分区范围,即在每个分区内对数据进行填充处理。
- 对于
Arabica Typica
分区,范围是600~900
。 - 对于
Gesha
分区,范围是1250~1700
。
- 对于
- 指定了
200
的step
,即被创建的新文档的altitude
间隔为200
。
聚合输出下面的文档:
[
{
_id: ObjectId("618c031814fbe03334480475"),
altitude: 600,
variety: 'Arabica Typica',
score: 68.3
},
{
_id: ObjectId("618c031814fbe03334480476"),
altitude: 750,
variety: 'Arabica Typica',
score: 69.5
},
{ variety: 'Arabica Typica', altitude: 800 },
{
_id: ObjectId("618c031814fbe03334480477"),
altitude: 950,
variety: 'Arabica Typica',
score: 70.5
},
{
_id: ObjectId("618c031814fbe03334480478"),
altitude: 1250,
variety: 'Gesha',
score: 88.15
},
{ variety: 'Gesha', altitude: 1450 },
{ variety: 'Gesha', altitude: 1650 },
{
_id: ObjectId("618c031814fbe03334480479"),
altitude: 1700,
variety: 'Gesha',
score: 95.5,
price: 1029
}
]
到了这里,关于MongoDB聚合:$densify的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!