MongoDB中如何向对象插入新属性且不覆盖原有字段?
问题与解决方案
问题描述
我想在MongoDB文档的AntiChannels和AntiRoles对象中添加Toggle属性,当前使用代码:
await config.findOneAndUpdate({ GuildID: GuildId }, { $set: { AntiChannels: { Toggle: "Enabled" } } }, { returnOriginal: true })
执行后AntiChannels下原有字段被移除,只剩Toggle。另外原本以为returnOriginal参数会返回原始文档,但实际没达到预期。附Schema定义:
AntiChannels: { Toggle: { type: String }, Actions: { Type: Number }, Time: { Type: Number }, }, AntiRoles: { Toggle: { type: String }, Actions: { Type: Number }, Time: { Type: Number }, }
一、添加新属性同时保留原有字段
你当前的写法是用$set直接覆盖了整个AntiChannels对象,导致原有字段被清空。要仅更新对象内的单个属性,需要使用点表示法指定嵌套字段:
单独给AntiChannels添加Toggle:
await config.findOneAndUpdate( { GuildID: GuildId }, { $set: { "AntiChannels.Toggle": "Enabled" } }, { returnOriginal: true } )
同时给AntiChannels和AntiRoles添加Toggle:
await config.findOneAndUpdate( { GuildID: GuildId }, { $set: { "AntiChannels.Toggle": "Enabled", "AntiRoles.Toggle": "Enabled" } }, { returnOriginal: true } )
这种写法只会修改指定的嵌套字段,不会影响AntiChannels/AntiRoles下的Actions、Time等原有字段。
二、returnOriginal参数的正确用法
returnOriginal参数的作用是控制更新操作返回的文档内容:
- 设置为
true时,返回更新前的原始文档 - 设置为
false时,返回更新后的新文档
注意:MongoDB 4.2+版本中,官方更推荐用returnDocument: "before"替代returnOriginal: true,returnDocument: "after"替代returnOriginal: false,两者功能完全一致,但returnDocument的语义更清晰。
示例:获取更新后的文档
const updatedDoc = await config.findOneAndUpdate( { GuildID: GuildId }, { $set: { "AntiChannels.Toggle": "Enabled" } }, { returnDocument: "after" } // 等价于returnOriginal: false )
内容的提问来源于stack exchange,提问作者treeqr
相关产品推荐
相关产品推荐

