如何部分更新MongoDB中的对象,以便新对象与现有对象叠加/合并
鉴于这个文件保存在MongoDB中
{ _id : ..., some_key: { param1 : "val1", param2 : "val2", param3 : "val3" } }
需要保存来自外部的具有关于param2
和param3
新信息的对象
var new_info = { param2 : "val2_new", param3 : "val3_new" };
我想合并/覆盖对象的现有状态的新字段,以便param1不会被删除
这样做
db.collection.update( { _id:...} , { $set: { some_key : new_info } }
将会导致MongoDB完全按照要求进行操作,并将some_key设置为该值。 取代旧的。
{ _id : ..., some_key: { param2 : "val2_new", param3 : "val3_new" } }
有什么方法让MongoDB只更新新的字段(没有明确指出)? 得到这个:
{ _id : ..., some_key: { param1 : "val1", param2 : "val2_new", param3 : "val3_new" } }
我正在使用Java客户端,但任何示例将不胜感激
如果我正确地理解了这个问题,你想用另一个文档的内容来更新一个文档,但是只有那些不存在的字段,并且完全忽略已经设置的字段(即使到另一个值)。
单一命令无法做到这一点。
你必须先查询文档,找出你想要的$set
,然后更新它(使用旧的值作为匹配的filter,以确保你没有获得并发的更新)。
你的问题的另一个解读是你对$set
感到满意,但不想明确设置所有的字段。 那么你将如何传递数据呢?
你知道你可以做到以下几点:
db.collection.update( { _id:...} , { $set: someObjectWithNewData }
我用自己的function解决了它。 如果要更新文档中的指定字段,则需要清楚地说明。
例:
{ _id : ..., some_key: { param1 : "val1", param2 : "val2", param3 : "val3" } }
如果你只想更新param2,那么这样做是错误的:
db.collection.update( { _id:...} , { $set: { some_key : new_info } } //WRONG
您必须使用:
db.collection.update( { _id:...} , { $set: { some_key.param2 : new_info } }
所以我写了一个这样的函数:
function _update($id, $data, $options=array()){ $temp = array(); foreach($data as $key => $value) { $temp["some_key.".$key] = $value; } $collection->update( array('_id' => $id), array('$set' => $temp) ); } _update('1', array('param2' => 'some data'));
Mongo允许你使用a来更新嵌套文件.
惯例。 看看: 在MongoDB中更新嵌套的文档 。 以下是关于合并更新的另一个问题,比如你正在寻找的合并更新:我相信: 通过“合并”文档的MongoDBprimefaces更新
您可以使用点符号来访问和设置对象内的深层字段,而不会影响这些对象的其他属性。
鉴于上面指定的对象:
> db.test.insert({"id": "test_object", "some_key": {"param1": "val1", "param2": "val2", "param3": "val3"}}) WriteResult({ "nInserted" : 1 })
我们可以更新some_key.param2
和some_key.param3
:
> db.test.findAndModify({ ... query: {"id": "test_object"}, ... update: {"$set": {"some_key.param2": "val2_new", "some_key.param3": "val3_new"}}, ... new: true ... }) { "_id" : ObjectId("56476e04e5f19d86ece5b81d"), "id" : "test_object", "some_key" : { "param1" : "val1", "param2" : "val2_new", "param3" : "val3_new" } }
你可以深入钻研。 这对于在不影响现有对象的情况下向对象添加新的属性也是有用的。
最好的解决scheme是从对象中提取属性,并使它们成为平面点符号键值对。 你可以使用例如这个库:
https://www.npmjs.com/package/mongo-dot-notation
它具有.flatten
function,允许您将对象更改为可以赋给$ set修饰符的平坦属性集,而不用担心现有的数据库对象的任何属性将被删除/覆盖而不需要。
采用mongo-dot-notation
文档:
var person = { firstName: 'John', lastName: 'Doe', address: { city: 'NY', street: 'Eighth Avenu', number: 123 } }; var instructions = dot.flatten(person) console.log(instructions); /* { $set: { 'firstName': 'John', 'lastName': 'Doe', 'address.city': 'NY', 'address.street': 'Eighth Avenu', 'address.number': 123 } } */
然后它形成完美的select器 – 它将更新只给定的属性。 编辑:我喜欢成为考古学家;)
它看起来像你可以设置isPartialObject这可能会完成你想要的。
我这样做是成功的:
db.collection.update( { _id:...} , { $set: { 'key.another_key' : new_info } } );
我有一个function,dynamic处理我的个人资料更新
function update(prop, newVal) { const str = `profile.${prop}`; db.collection.update( { _id:...}, { $set: { [str]: newVal } } ); }
注意:“configuration文件”是特定于我的实现,它只是您想要修改的密钥的string。
使用$ set做这个过程
.update({"_id": args.dashboardId, "viewData._id": widgetId}, {$set: {"viewData.$.widgetData": widgetDoc.widgetData}}) .exec() .then(dashboardDoc => { return { result: dashboardDoc }; });