正常操作当中,使用点号(.)来操作嵌套对象字段。使用$符号来获取操作数组字段。但mongodb并未限制定义字段名称时,不可以包含点号和$符号。只是在使用时,对包含这两种符号的字段名称,增加了一些限制。
使用限制
Insert操作中使用$开头字段
允许插入$开头定义字段名称的数据
$开头定义的字段,可以位于文档的顶级,也可以位于文档的嵌套文档对象中,下面语句可以成功执行
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
}
})
{
"acknowledged" : true,
"insertedId" : ObjectId("655ebf9869185fac9ce3ce91")
}
db.books.find()
{
"_id" : ObjectId("655ebf9869185fac9ce3ce91"),
"$id" : "h1961-01",
"location" : {
"$db" : "novels",
"$ref" : "2007042768",
"$inc" : true
}
}
update操作中使用$开头的字段
//第一次执行, 集合中没有数据,转变为插入操作, 成功
db.expenses.updateOne({"date": "2021-07-07"}, {$set: {
"phone": 25.17,
"$hotel": 321.10
}}, {upsert: true})
{
"acknowledged" : true,
"matchedCount" : 0,
"modifiedCount" : 0,
"upsertedId" : ObjectId("655ec130b37e0bb6c6d08bfe")
}
//第二次执行, 也返回正确的结果,因为没有更新字段值,所以没有更新。
db.expenses.updateOne({"date": "2021-07-07"}, {$set: {
"phone": 25.17,
"$hotel": 321.10
}}, {upsert: true})
{
"acknowledged" : true,
"matchedCount" : 1,
"modifiedCount" : 0
}
//修改字段$hotel的值,更新失败
db.expenses.updateOne({"date": "2021-07-07"}, {$set: {
"phone": 25.17,
"$hotel": 321.11
}}, {upsert: true})
WriteError({
"index" : 0,
"code" : 52,
"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.",
"op" : {
"q" : {
"date" : "2021-07-07"
},
"u" : {
"$set" : {
"phone" : 25.17,
"$hotel" : 321.11
}
},
"multi" : false,
"upsert" : true
}
})
//插入测试数据
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"}
})
{
"acknowledged" : true,
"matchedCount" : 1,
"modifiedCount" : 1
}
//修改$rooms.br的值,成功
db.housing.update({
"_id": "E123"
},{
$set: {"$rooms.br": 3}
})
{
"acknowledged" : true,
"matchedCount" : 1,
"modifiedCount" : 1
}
//修改$room字段的值,失败
db.housing.update({
"_id": "E123"
},{
$set: {"$rooms": {
br: 4,
bath: 2
}}
WriteError({
"index" : 0,
"code" : 52,
"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.",
"op" : {
"q" : {
"_id" : "E123"
},
"u" : {
"$set" : {
"$rooms" : {
"br" : 4,
"bath" : 2
}
}
},
"multi" : false,
"upsert" : false
}
})
})
//把address.$street字段值修改成对象,成功
db.housing.update({
"_id": "E123"
}, {
$set: {
"address.$street": {
"city": "NYK",
"name": "Elm Road"
}
}
})
{
"acknowledged" : true,
"matchedCount" : 1,
"modifiedCount" : 1
}
db.inventory.insertOne({
"part": "AB305",
"$bin": 200,
"quantity": 100,
"pricing": {
sale: true,
"$discount": 60
}
})
{
"acknowledged" : true,
"insertedId" : ObjectId("655ef22e69185fac9ce3ce92")
}
//更新嵌套字段中$discount字段
db.inventory.findAndModify({
query: {
"part": {$eq: "AB305"}
},
update: {
$inc: {"pricing.$discount": 10}
}
})
{
"_id" : ObjectId("655ef22e69185fac9ce3ce92"),
"part" : "AB305",
"$bin" : 200,
"quantity" : 100,
"pricing" : {
"sale" : true,
"$discount" : 60
}
}
//使用$开头的顶级字段作为查询条件更新数据
db.inventory.findAndModify({
query: {
$expr: {
$eq: [{$getField: {$literal: "$bin" }}, 200]
}
},
update: {
$inc: {"quantity": 10}
}
})
{
"_id" : ObjectId("655ef22e69185fac9ce3ce92"),
"part" : "AB305",
"$bin" : 200,
"quantity" : 100,
"pricing" : {
"sale" : true,
"$discount" : 70
}
}
在aggregation中操作$开头的字段
使用aggregation更新字段时, 在$replaceWith方法使用$setField, $getField, $literal更新带有$字符开头的字段
db.school.insertOne({
"_id": 10001,
"$term": "fall",
"registered": true,
"grade": 4
})
{
"acknowledged" : true,
"insertedId" : 10001
}
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
}