对于 AI 代理:可在 https://www.mongodb.com/zh-cn/docs/llms.txt 获取文档索引—通过在任何 URL 路径后添加 .md 可获取所有页面的 Markdown 版本。

$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.unit,step 必须是整数。否则,step 可以是任何数值。

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

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

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

  • millisecond

  • second

  • minute

  • hour

  • day

  • week

  • month

  • quarter

  • year

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

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

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

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

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

  • 8.1 版本中的新增功能:

    field 与 partitionByFields 数组中的任何字段共享其前缀。例如,示例的以下组合field 和 partitionByFields 会导致错误:

    • field: "timestamp", partitionByFields: ["timestamp"]

    • field: "timestamp", partitionByFields: ["timestamp.hours"]

    • field: "timestamp.hours", partitionByFields: ["timestamp"]

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

  • 求值为非字符串值。

  • 以 $ 开头。

如果 range.bounds 是一个数组:

  • 下限值表示新增文档的起始值,与集合中已有的文档无关。

  • 下限包含在内。

  • 不含上边界。

  • $densify 不会过滤字段值超出指定范围的文档。

注意

从MongoDB8.0 开始,$densify 将具有相等下限和上限的边界视为空设立,并且不会生成将该边界作为字段值的文档。

在以前的版本中,$densify 将具有相等下限和上限的边界视为闭区间,并在集合尚未包含具有边界值的文档时生成具有边界值的文档作为字段值。

示例, 的范围.bounds [10, 10]10在 之前的版本中生成字段值为 的额外的文档,但在8.08.0 及更高版本中不会生成此类文档。

$densify 如果生成的文档数量超过 internalQueryMaxAllowedDensifyDocs 参数设置的限制,则返回错误。默认情况下,此限制为 500,000 个文档。

要允许生成更多的文档,请增加 internalQueryMaxAllowedDensifyDocs 参数的值。

$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 范围,这意味着数据在每个分区的整个现有文档范围内进行密集化。

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

该聚合输出以下文档:

[ { _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 Typica 和 Gesha 咖啡分别创建一个分组。

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

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

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

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

该聚合输出以下文档:

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

给本页内容打分