以美元符号开头的字段名
本节总结了不同的插入和更新操作如何处理美元($
)前缀的字段名。
插入操作
以美元($
)前缀的字段名允许用作插入操作中的顶层和嵌套字段名。
db.sales.insertOne( { "$price": 50.00, "quantity": 30 } )
以美元($
)前缀的字段名允许在插入操作中使用其他保留字。例如,操作符名称$inc
可以作为字段名,以及像id
、db
和ref
这样的单词。
db.books.insertOne( { "$id": "h1961-01", "location": { "$db": "novels", "$ref": "2007042768", "$inc": true } } )
在upsert操作期间创建新文档的更新被视为insert
操作,而不是update
操作,以验证字段名。Upserts可以接受美元($
)前缀字段。然而,upserts是一个特殊情况,并且类似的更新操作如果更新操作的match
部分选择了一个现有文档,可能会引发错误。
此代码示例具有upsert: true
,因此如果集合中尚未包含与查询词匹配的文档,它将插入新文档,即{ "date": "2021-07-07" }
。如果此示例代码匹配现有文档,则更新将失败,因为$hotel
是美元($
)前缀。
db.expenses.updateOne( { "date": "2021-07-07" }, { $set: { "phone": 25.17, "$hotel": 320.10 } }, { upsert: true } )
文档替换更新
更新运算符要么用新文档替换现有字段,要么修改这些字段。当更新执行替换操作时,不允许使用美元($
)前缀的字段作为顶级字段名称。
考虑一个如下的文档:
{ "_id": "E123", "address": { "$number": 123, "$street": "Elm Road" }, "$rooms": { "br": 2, "bath": 1 } }
您可以使用一个更新运算符替换现有文档以修改address.$street
字段,但您不能以这种方式更新$rooms
字段。
db.housing.updateOne( { "_id": "E123" }, { $set: { "address.$street": "Elm Ave" } } )
文档修改更新
当更新修改而不是替换现有文档字段时,美元($
)前缀字段可以是顶级字段名称。可以直接访问子字段,但需要辅助方法来访问顶级字段。
考虑一个包含如下库存记录的集合:
{ _id: ObjectId("610023ad7d58ecda39b8d161"), "part": "AB305", "$bin": 200, "quantity": 100, "pricing": { sale: true, "$discount": 60 } }
pricing.$discount
子字段可以直接查询。
db.inventory.findAndModify( { query: { "part": { $eq: "AB305" } }, update: { $inc: { "pricing.$discount": 10 } } } )
使用$getField
和$literal
来访问顶级$bin
字段的值。
db.inventory.findAndModify( { query: { $expr: { $eq: [ { $getField: { $literal: "$bin" } }, 200 ] } }, update: { $inc: { "quantity": 10 } } } )
使用聚合管道更新
在$replaceWith
阶段使用$setField
、$getField
和$literal
来修改聚合管道
中美元符号($
)前缀的字段。
考虑一个学校记录集合
{ "_id": 100001, "$term": "fall", "registered": true, "grade": 4 }
使用一个管道创建一个新的春季学期集合,以更新美元符号($
)前缀的$term
字段。
db.school.aggregate( [ { $match: { "registered": true } }, { $replaceWith: { $setField: { field: { $literal: "$term" }, input: "$$ROOT", value: "spring" } } }, { $out: "spring2022" } ] )
一般限制
除了上述存储验证规则外,还有一些关于使用美元符号($
)前缀的字段名的一般限制。这些字段不能
被索引
作为分片键的一部分使用
使用
$jsonSchema
进行验证使用转义序列进行修改
与字段级加密一起使用
作为
_id
文档的子字段使用
警告
使用美元符号($)和句点(.)可能导致数据丢失
当在旧于MongoDB 5.0的服务器上使用未确认写入(写关注 w=0
)与美元符号($
)前缀的字段名或包含句点(.
)的字段名一起使用时,有可能导致数据丢失。
在执行 insert
、update
和 findAndModify
命令时,与 5.0 兼容的驱动程序移除了对使用字段名为美元符号($
)前缀或包含点(.
)的文档的限制。这些字段名在早期版本驱动程序中会生成客户端错误。
无论驱动程序连接到哪个服务器版本,都会移除这些限制。如果 5.0 驱动程序向旧服务器发送文档,该文档将被拒绝而不会发送错误。
警告
关于美元符号($)和点(.)的导入和导出注意事项
从 MongoDB 5.0 开始,文档字段名可以以美元符号($
)开头,并且可以包含点(.
)。然而,在 mongoimport
和 mongoexport
中,某些情况下使用这些字符的字段名可能不会按预期工作。
MongoDB 扩展 JSON v2 无法区分类型包装器和偶然与类型包装器同名的数据字段。不要在可能包含美元符号($
)前缀的相应 BSON 表示的上下文中使用扩展 JSON 格式。DBRef 机制是这一通用规则的一个例外。
在使用点(.
)作为字段名字符的 mongoimport
和 mongoexport
上也存在限制。由于 CSV 文件使用点(.
)表示数据层次结构,字段名中的点(.
)将被错误地解释为嵌套级别。