更新最初为null的嵌套属性

时间:2017-07-15 00:29:44

标签: mongodb mongoose mongodb-query

我在文档中有一个可能为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})"
}
})

2 个答案:

答案 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" }
 }
})