Docs 菜单

Docs 主页开发应用程序MongoDB Manual

字段名称,带句点 ( . ) 和美元符号 ( $ )

在此页面上

  • 概述
  • 插入操作
  • 文档替换更新
  • 文档修改更新
  • 使用聚合管道进行更新。
  • 一般限制

MongoDB 5.0 改进了对以美元 ($) 为前缀或包含句点 (.) 的字段名称的支持。存储数据的验证规则已更新,以便更轻松地处理使用这些字符的数据源。

在大多数情况下,使用类似字段名称存储的数据不能直接访问。您需要在访问这些字段的查询中使用诸如 $getField$setField$literal 等辅助方法。

对于所有类型的存储操作,字段名称的验证规则并不相同。本页总结了不同的插入和更新操作如何处理美元 ($) 前缀的字段名称。

允许以美元 ($) 为前缀的字段作为插入操作的顶层和嵌套字段名。

db.sales.insertOne( {
"$price": 50.00,
"quantity": 30
} )

附带美元符号 ($) 前缀的字段可在使用其他保留字的插入操作中使用。$inc 一类的运算符名称以及类似 iddbref 的词可用作字段名称。

db.books.insertOne( {
"$id": "h1961-01",
"location": {
"$db": "novels",
"$ref": "2007042768",
"$inc": true
} } )

对字段名验证而言,在更新或插入 (upsert) 期间创建新文档的更新被视为 insert 而非 updateupsert 可接受以美元符号 ($) 为前缀的字段。不过,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" } }
)

使用$setField作为聚合管道的一部分来更新顶级美元 ( $ ) 前缀字段,例如$rooms

当更新修改而不是替换现有文档字段时,美元 ($) 前缀字段可以是顶级字段名称。可以直接访问子字段,但您需要一个辅助方法来访问顶级字段。

提示

另请参阅:

考虑包含此类库存记录文档的集合:

{
_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更新findAndModify命令时,5.0 兼容的驱动程序取消了对使用字段名称以美元 ( $ ) 为前缀或包含句点 ( . ) 的文档的限制。在早期的驱动程序版本中,这些字段名称会产生客户端错误。

无论驱动程序连接到哪个服务器版本,这些限制均会被删除。如果 5.0 驱动程序将文档发送到较旧的服务器,则会拒绝该文档,而不会发送错误。

警告

使用美元符号 ($) 和句点 (.) 时的导入和导出问题

从 MongoDB 5开始。 0 ,文档字段名称可以以美元符号 ( $ ) 为前缀,并且可以包含句点 ( . )。但是,在某些情况下,如果字段名称使用mongoimportmongoexport字符,则它们可能无法按预期运行。

MongoDB 扩展 JSON v2 无法区分类型封装器和碰巧与类型封装器同名的字段。不要在相应的 BSON 表示可能包含美元 ($) 前缀键的上下文中使用扩展 JSON 格式。DBRef 机制是该一般规则的例外。

在字段名称中使用带句点 ( . ) 的mongoimportmongoexport也有限制。由于 CSV 文件使用句点 ( . ) 表示数据层次结构,因此字段名称中的句点 ( . ) 将被误解为嵌套级别。

← 分布式查询