自5.0版本开始,针对以dollar($)字符开头的字段名称和包含点号(.)的字段名称,mongodb在使用上做了增强。这对带有这两个符号字段名称的数据存储,mongodb修改了验证规则,操作带有这两种符号的字段,变得更加简单。
正常操作当中,使用点号(.)来操作嵌套对象字段。使用$符号来获取操作数组字段。但mongodb并未限制定义字段名称时,不可以包含点号和$符号。只是在使用时,对包含这两种符号的字段名称,增加了一些限制。
本文依据官方文档,对带$开头的字段名称操作,进行了整理。
带有$符号开头的字段,mongodb做了下面的限制
$开头定义的字段,可以位于文档的顶级,也可以位于文档的嵌套文档对象中,下面语句可以成功执行
db.housing.insertOne({
"_id":"E123",
"address": {
"$number":123,
"$street": "Elm Road"
},
"$rooms": {
"br": 2,
"bath": 1
}
})
如$inc, $id, $db, $ref都可以作为字段名称。
db.books.insertOne({
"$id": "h1961-01",
"location": {
"$db": "novels",
"$ref": "2007042768",
"$inc": true
}
})
//第一次执行, 集合中没有数据,转变为插入操作, 成功
db.expenses.updateOne({"date": "2021-07-07"}, {$set: {
"phone": 25.17,
"$hotel": 321.10
}}, {upsert: true})
//修改字段$hotel的值,更新失败
db.expenses.updateOne({"date": "2021-07-07"}, {$set: {
"phone": 25.17,
"$hotel": 321.11
}}, {upsert: true})
"errmsg" : "The dollar ($) prefixed field '$hotel' in '$hotel' is not allowed in the context of an update's replacement document. Consider using an aggregation pipeline with $replaceWith.",
//插入测试数据
db.housing.insertOne({
"_id":"E123",
"address": {
"$number":123,
"$street": "Elm Road"
},
"$rooms": {
"br": 2,
"bath": 1
}
})
//修改嵌套字段中$street字段的值,成功
db.housing.updateOne({
"_id": "E123"
}, {
$set: {"address.$street": "Elm Ave"}
})
//修改$rooms.br的值,成功
db.housing.update({
"_id": "E123"
},{
$set: {"$rooms.br": 3}
})
//修改$room字段的值,失败
db.housing.update({
"_id": "E123"
},{
$set: {"$rooms": {
br: 4,
bath: 2
}}
"errmsg" : "The dollar ($) prefixed field '$rooms' in '$rooms' is not allowed in the context of an update's replacement document. Consider using an aggregation pipeline with $replaceWith.",
//把address.$street字段值修改成对象,成功
db.housing.update({
"_id": "E123"
}, {
$set: {
"address.$street": {
"city": "NYK",
"name": "Elm Road"
}
}
})
db.inventory.insertOne({
"part": "AB305",
"$bin": 200,
"quantity": 100,
"pricing": {
sale: true,
"$discount": 60
}
})
//更新嵌套字段中$discount字段
db.inventory.findAndModify({
query: {
"part": {$eq: "AB305"}
},
update: {
$inc: {"pricing.$discount": 10}
}
})
//使用$开头的顶级字段作为查询条件更新数据
db.inventory.findAndModify({
query: {
$expr: {
$eq: [{$getField: {$literal: "$bin" }}, 200]
}
},
update: {
$inc: {"quantity": 10}
}
})
使用aggregation更新字段时, 在$replaceWith方法使用$setField, $getField, $literal更新带有$字符开头的字段
db.school.insertOne({
"_id": 10001,
"$term": "fall",
"registered": true,
"grade": 4
})
db.school.aggregate([{
$match: {"registered": true}
}, {
$replaceWith: {
$setField: {
field: { $literal: "$term" },
input: "$$ROOT",
value: "spring"
}
}
}, {
$out: "spring2022"
}])
db.spring2022.find()
{
"_id" : 10001,
"$term" : "spring",
"registered" : true,
"grade" : 4
}