以美元为前缀的字段名称
本节总结了不同的插入和更新操作如何处理美元 ( $
) 前缀字段名称。
插入操作
允许以美元 ($
) 为前缀的字段作为插入操作的顶层和嵌套字段名。
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
。upsert 可接受以美元符号 ($
) 为前缀的字段。不过,upsert 是一种特例,如果更新中的 match
部分选择的是现有文档,类似的更新操作可能会引发错误。
此代码示例中包含 upsert: true
,因此如果集合尚未包含与查询词 { "date": "2021-07-07" }
匹配的文档,MongoDB 会插入一份新文档。如果此示例代码与现有文档匹配,则更新失败,因为 $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 文件使用句点 (.
) 表示数据层次结构,因此字段名称中的句点 (.
) 会被误读为嵌套级别。