Mongodb操作带有$符号开头的字段

自5.0版本开始,针对以dollar($)字符开头的字段名称和包含点号(.)的字段名称,mongodb在使用上做了增强。这对带有这两个符号字段名称的数据存储,mongodb修改了验证规则,操作带有这两种符号的字段,变得更加简单。

正常操作当中,使用点号(.)来操作嵌套对象字段。使用$符号来获取操作数组字段。但mongodb并未限制定义字段名称时,不可以包含点号和$符号。只是在使用时,对包含这两种符号的字段名称,增加了一些限制。

本文依据官方文档,对带$开头的字段名称操作,进行了整理。

使用限制

带有$符号开头的字段,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
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值