迁移未定义数据和查询
从 MongoDB 8.0 开始,在相等匹配表达式中对null
的比较不匹配undefined
值。
例如,考虑以下文档和查询
// people collection [ { _id: 1, name: null }, { _id: 2, name: undefined }, { _id: 3, name: [ "Gabriel", undefined ], { _id: 4, names: [ "Alice", "Charu" ] } ]
db.people.find( { name: null } )
MongoDB 8.0 之前,前面的查询会匹配以下文档:
字段
name
为null
(_id: 1
)字段
name
为undefined
或包含undefined
数组元素(_id: 2
和_id: 3
)字段
name
不存在(_id: 4
)
从 MongoDB 8.0 开始,前面的查询不会匹配字段 name
为 undefined
或包含 undefined
数组元素的文档。查询仅匹配以下文档:
name
字段为null
或包含一个包含null
数组元素的_id: 1
字段
name
不存在(_id: 4
)
此查询行为变更也会影响以下操作
为了适应这一行为变更,你可以
注意
undefined
是一个已弃用的BSON类型。MongoDB Shell和驱动程序的新版本在执行插入和更新操作时,会自动将undefined
值转换为null
。本页面的指导适用于包含来自旧版本驱动程序或旧版mongo
Shell的undefined
值的部署。
删除未定义字段
如果你不需要在文档中保留具有undefined
值的字段,你可以删除这些字段。MongoDB灵活的数据模型意味着你的集合的文档字段不需要保持一致,因此你可以从文档的子集中删除特定的字段。
如何从你的文档中删除未定义的字段取决于你是否知道要删除的字段名。如果你知道字段名,则操作性能更高,因为它可以使用索引。
请参阅以下内容
删除已知名称的字段
如果你知道包含要删除的undefined
值的字段名,可以使用以下示例。示例更新people
集合以删除
如果其值是标量值
undefined
,则name
字段。name
字段中的undefined
数组元素。
db.people.updateMany( { name: { $type: "undefined" } }, [ { $set: { "name": { $cond: { // When "name" is an array, convert { name: [ "Alice", undefined ] } // to { name: [ "Alice" ] } if: { $eq: [ { $type: "$name" }, "array" ] }, then: { $filter: { input: "$name", cond: { $not: { $eq: [ { $type: "$$this" }, "undefined" ] } } }, }, // When "name" is scalar undefined, remove it else: "$$REMOVE" } } } } ] )
运行操作后,people
集合包含以下文档
[ { _id: 1, name: null }, { _id: 2 }, { _id: 3, name: [ "Gabriel" ] } { _id: 4, names: [ "Alice", "Charu" ] } ]
删除具有未知名称的字段
如果您不知道哪些字段包含 undefined
值,请使用以下示例删除所有顶层 undefined
字段。
注意
当您未指定更新操作的字段名称时,该操作的性能不佳,因为查询无法使用索引。如果您在大型集合上运行以下示例,查询可能很慢且资源密集。
以下示例从 people
集合中删除值是 undefined
的顶层文档字段。
db.people.updateMany( { }, [ { $replaceWith: { // Detect undefined top-level fields under the root and remove them $arrayToObject: { $filter: { input: { $objectToArray: "$$ROOT" }, cond: { $not: { $eq: [ { $type: "$$this.v" }, "undefined" ] } } } } } } ] )
运行操作后,people
集合包含以下文档
[ { _id: 1, name: null }, { _id: 2 }, { _id: 3, name: [ "Gabriel", undefined ] } { _id: 4, names: [ "Alice", "Charu" ] } ]
注意
前面的方法仅修改顶层字段。具有 _id: 3
的文档仍然包含 undefined
值,因为该值出现在数组中。
将未定义值更新为 Null
您可以将 undefined
数据值更新为 null
数据类型。使用这种方法将数据迁移到已弃用的 undefined
数据类型,同时保留文档字段。
如何更新未定义字段取决于您是否知道要更新的字段名称。如果您知道字段名称,则操作性能更好,因为它可以使用索引。
请参阅以下内容
使用已知名称更新字段
如果您知道包含您想设置为 null
的 undefined
值的字段名称,请使用以下示例。以下示例更新 people
集合,将这些值设置为 null
如果其值是标量值
undefined
,则name
字段。undefined
数组元素出现在name
字段中。
db.people.updateMany( { name: { $type: "undefined" } }, [ { $set: { "name": { $cond: { // When "name" is an array, convert { name: [ "Alice", undefined ] } // to { name: [ "Alice", null ] } if: { $eq: [ { $type: "$name" }, "array" ] }, then: { $map: { input: "$name", in: { $cond: { if: { $eq: [ { $type: "$$this" }, "undefined" ] }, then: null, else: "$$this" } } }, }, // When "name" is the scalar undefined, convert to null else: null } } } } ] )
运行操作后,people
集合包含以下文档
[ { _id: 1, name: null }, { _id: 2, name: null }, { _id: 3, name: [ "Gabriel", null ] } { _id: 4, names: [ "Alice", "Charu" ] } ]
使用未知名称更新字段
如果您不知道哪些字段包含 undefined
值,请使用以下示例将所有顶层 undefined
字段设置为 null
。
注意
当您未指定更新操作的字段名称时,该操作的性能不佳,因为查询无法使用索引。如果您在大型集合上运行以下示例,查询可能很慢且资源密集。
以下示例更新 people
集合,将顶层文档字段中的 undefined
设置为 null
db.people.updateMany( { }, [ { $replaceWith: { // Detect undefined top-level fields under the root and replace them with null $arrayToObject: { $map: { input: { $objectToArray: "$$ROOT" }, in: { $cond: { if: { $eq: [ { $type: "$$this.v" }, "undefined" ] }, then: { k: "$$this.k", v: null }, else: "$$this" } } } } } } ] )
运行操作后,people
集合包含以下文档
[ { _id: 1, name: null }, { _id: 2, name: null }, { _id: 3, name: [ "Gabriel", undefined ] } { _id: 4, names: [ "Alice", "Charu" ] } ]
注意
前面的方法仅修改顶层字段。具有 _id: 3
的文档仍然包含 undefined
值,因为该值出现在数组中。
更新查询以匹配未定义值
如果您无法将数据类型从 null
迁移到 undefined
,则可以重新编写查询以匹配未定义值。如果您采用这种方法,您的数据仍将包含已弃用的 undefined
BSON 类型。
若要使对 null
的查询匹配未定义值,请添加一个显式匹配 undefined
类型的查询谓词。例如,以下查询匹配 name
为 undefined
、null
或缺失的文档
db.people.find( { $or: [ { name: null }, { name: { $type: "undefined" } } ] } )
该查询返回 people
集合中的所有文档
[ { _id: 1, name: null }, { _id: 2, name: undefined }, { _id: 3, name: [ "Gabriel", undefined ], { _id: 4, names: [ "Alice", "Charu" ] } ]