Docs 菜单
Docs 主页
/
MongoDB Manual
/ / /

$densify(聚合)

在此页面上

  • 定义
  • 语法
  • 行为和限制
  • 示例
$densify

5.1 版本中的新功能

在文档序列中创建新文档,其中缺少字段中的某些值。

您可以使用 $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> ,请使用点表示法。

有关限制,请参阅 field 限制

Optional

该字段集作为复合键,对文档进行分组。在 $densify 阶段,每组文档称为一个分区

如果省略此字段,$densify 将使用整个集合的一个分区。

有关示例,请参阅用分区密集化

有关限制,请参阅 partitionByFields 限制

必需

指定如何密集化数据的对象。

必需

您可以将 range.bounds 指定为其中之一:

  • An array: [ < lower bound >, < upper bound > ],

  • 字符串:"full""partition"

如果 bounds 是数组:

  • $densify 添加跨越指定边界内的取值范围的文档。

  • 边界的数据类型必须与被密集化字段的数据类型一致。

  • 有关行为详情,请参阅 range.bounds 行为

如果 bounds"full"

  • $densify 添加的文档跨越了正在密集化的 field 的全部取值范围。

如果 bounds"partition"

  • $densify 将文档添加到每个分区,就像在每个分区上单独运行 full 范围密集化一样。

必需

每个文档中字段值增加的数额。$densify 为现有文档之间的每个 step 创建一个新文档。

如果指定 range.unitstep 必须是整数。否则,step 可以是任何数值。

如果字段是日期,则为必填项。

字段中递增日期值时应用于步骤字段的单位。

您可以将 unit 的以下值之一指定为字符串:

  • millisecond

  • second

  • minute

  • hour

  • day

  • week

  • month

  • quarter

  • year

有关示例,请参阅密集化时间序列数据

对于包含指定字段的文档,如果 $densify 出现错误,则表示:

  • 集合中的任何文档都有日期类型的 field 值,且未指定单位字段。

  • 集合中的任何文档都有数值类型的 field 值,并指定了单位字段。

  • field 名称以 $ 开头。如果要密集化字段,必须重新命名。如需重命名字段,请使用 $project

$densify 会出错,如果 partitionByFields 数组中的任何字段名称:

  • 求值为非字符串值。

  • $ 开头。

如果 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: 1timestamp 字段增加 1 个单位。

      • unit: hour 按小时密集化 timestamp 字段。

      • bounds: [ ISODate("2021-05-18T00:00:00.000Z"), ISODate("2021-05-18T08:00:00.000Z") ] 设置密集化的时间范围。

在以下输出中,$densify 阶段填补了 00:00:0008: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 来加密每种咖啡 varietyaltitude 字段:

db.coffee.aggregate( [
{
$densify: {
field: "altitude",
partitionByFields: [ "variety" ],
range: {
bounds: "full",
step: 200
}
}
}
] )

聚合示例:

  • variety 对文档分区,为 Arabica TypicaGesha 咖啡分别创建一个分组。

  • 指定 full 范围,这意味着数据在每个分区的整个现有文档范围内进行密集化。

  • 指定 step200,意味着以 200altitude 间隔创建新文档。

该聚合输出以下文档:

[
{
_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 创建的文档:

全范围密集化后咖啡集合的状态
点击放大
  • 较深的方块表示集合中的原始文档。

  • 较浅的方块表示使用 $densify 创建的文档。

此示例使用 $densify 仅加密每个 variety 内的 altitude 字段的间隙:

db.coffee.aggregate( [
{
$densify: {
field: "altitude",
partitionByFields: [ "variety" ],
range: {
bounds: "partition",
step: 200
}
}
}
] )

聚合示例:

  • variety 对文档分区,为 Arabica TypicaGesha 咖啡分别创建一个分组。

  • 指定 partition 范围,这意味着数据在每个分区内均已加密。

    • 对于 Arabica Typica 分区,范围是 600-950

    • 对于 Gesha 分区,范围是 1250-1700

  • 指定 step200,意味着以 200altitude 间隔创建新文档。

该聚合输出以下文档:

[
{
_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
}
]

该图片直观展示了使用 $densify 创建的文档:

分区范围密集化后的咖啡集合状况
点击放大
  • 较深的方块表示集合中的原始文档。

  • 较浅的方块表示使用 $densify 创建的文档。

后退

$currentOp