我在文档中有一个可能为null的字段;我想更新该文档的内部字段,如果该字段为空,则将该字段创建为对象。作为示范:
say the document looks like this: {
id: "xyz",
name: null
}
db.update({id: "xyz"}, {$set: {"name.first": "Joe"}})
现在,在运行时我不知道name字段是否为null。如果name
为空,我只想将{ first: "Joe" }
更新为name
。
我实际上是通过Mongoose模型来实现的,其模式是这样的:
{
name: {
default: null,
type: {
first: {
type: String
},
middle: {
type: String,
},
last: {
type: String,
},
display: {
type: String,
}
}
}
}
有没有办法在一个查询中执行更新?或者我是否需要分两步执行(查询以获取name
的当前值,然后对其进行扩充并设置它?)
编辑:这是我在控制台中运行时得到的结果
> db.users.findAndModify({ query: { _id: ObjectId("596958d60782a56eb3ba3d93") }, update: { '$set': { 'name.display': 'dfgdfgfgf' } }})
2017-07-14T20:13:45.855-0400 findAndModifyFailed failed: {
"value" : {
"_id" : ObjectId("596958d60782a56eb3ba3d93"),
"sessionID" : "2bPzS2lqkDxN-3XEQRw60GAB93XODi4Y",
"profilePhotoURL" : null,
"name" : null,
"__v" : 0
},
"errmsg" : "exception: cannot use the part (name of name.display) to traverse the element ({name: null})",
"code" : 16837,
"ok" : 0
} at src/mongo/shell/collection.js:614
> db.users.update({ _id: ObjectId("596958d60782a56eb3ba3d93") }, {$set: {"name.display": "sdfsdfsfd"}})
WriteResult({
"nMatched" : 0,
"nUpserted" : 0,
"nModified" : 0,
"writeError" : {
"code" : 16837,
"errmsg" : "cannot use the part (name of name.display) to traverse the element ({name: null})"
}
})
答案 0 :(得分:1)
我最近偶然发现了同样的问题,我设法使用从 4.2 版开始的 Mongodb 附带的 aggregation pipeline for updates 功能和 $ifNull 运算符来解决它。
举个例子,如果我有以下文件:
db.test.insertOne({ _id: "foo", a: null })
我想将 a 设置为一个对象,例如:
a: { b: 1 }
您可以使用以下语句:
db.test.updateOne({_id: "foo"}, [{$set: {'a.b': { $ifNull: [1, 1] } } }])
这样做的作用是,如果 'ab' 为或不为 null,它将用值 1 更新它。这种方法消除了事先知道该字段是否为 null 或是否已初始化的需要。
答案 1 :(得分:0)
使用MongoDB,您可以使用findAndModify(),这将允许您执行查询并仅更新匹配的文档。
操作以原子方式执行,因此一旦发现没有其他操作可以读取文档,直到更新发生。这在其他情况下很有用。这也是您在API中writeConcern
可调整的原因。
示例:强>
db.collection.findAndModify({
query: {
name: null
},
update: {
name: { first: "Joe" }
}
})