如何部分MongoDB中更新的对象,因此新对象将覆盖/与现有的合并如何部分MongoDB中更新的对象

2019-05-13 15:20发布

鉴于这种文档保存在MongoDB中

{
   _id : ...,
   some_key: { 
        param1 : "val1",
        param2 : "val2",
        param3 : "val3"
   }
}

对新信息的对象param2param3来自外部世界的需要被保存

var new_info = {
    param2 : "val2_new",
    param3 : "val3_new"
};

我想合并/覆盖在物体的存在状态的新领域,使参数1不会被删除

这样做

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客户端,但任何例子可以理解

Answer 1:

如果我理解正确的问题,要更新与另一个文件中的内容,而只是说是不存在的字段的文档,并且完全无视已经被设定的字段(即使为其他值)。

有没有办法做,在一个单一的命令。

你必须首先查询文件,找出你想要什么$set ,然后更新它(使用旧的值作为匹配过滤器,确保你没有得到之间并发更新)。


你的问题的另一种解读是,你很高兴与$set ,但不想明确设置所有字段。 你将如何在数据传递呢?

你知道你可以做到以下几点:

db.collection.update(  { _id:...} , { $set: someObjectWithNewData } 


Answer 2:

我用我自己的功能解决了这个问题。 如果你想在文件更新指定字段你需要清楚地解决这个问题。

例:

{
    _id : ...,
    some_key: { 
        param1 : "val1",
        param2 : "val2",
        param3 : "val3"
    }
}

如果你想只更新参数2,这是不对的事情:

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'));


Answer 3:

你可以使用点符号来访问和设置字段内心深处的对象,而不会影响这些对象的其他属性。

鉴于上面指定的对象:

> db.test.insert({"id": "test_object", "some_key": {"param1": "val1", "param2": "val2", "param3": "val3"}})
WriteResult({ "nInserted" : 1 })

我们可以只更新some_key.param2some_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"
    }
}

您可以钻研像你一样深。 这也是增加新的属性的对象,而不会影响现有的有用。



Answer 4:

最好解决方案是从对象中提取属性,并使其平坦点符号键 - 值对。 你可以使用例如这个库:

https://www.npmjs.com/package/mongo-dot-notation

.flatten功能,允许您更改对象变成平坦的一套可再给予$设置修改属性,没有你的存在的数据库对象的任何属性将无需被删除/覆盖的担忧。

来自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
  }
}
*/

然后它形成完美的选择 - 它会更新只给性能。 编辑:我想成为考古学家有时;)



Answer 5:

蒙哥允许您更新使用嵌套的文件. 惯例。 请看: 更新MongoDB中嵌套的文件 。 下面是关于合并更新过去的另一个问题,就像你找我一个相信: MongoDB的原子更新通过“合并”的文件



Answer 6:

我成功做这种方式:

db.collection.update(  { _id:...} , { $set: { 'key.another_key' : new_info  } } );

我有一个动态地处理我的个人资料更新功能

function update(prop, newVal) {
  const str = `profile.${prop}`;
  db.collection.update( { _id:...}, { $set: { [str]: newVal } } );
}

注:“配置文件”是针对我的实现,这是你要修改的关键只是字符串。



Answer 7:

它看起来像您可以设置isPartialObject可能完成你想要的。



Answer 8:

是的,最好的办法是在对象符号转换成平键值字符串表示,在此评论中提到: https://stackoverflow.com/a/39357531/2529199

我想强调使用此NPM库的另一种方法: https://www.npmjs.com/package/dot-object它可以让你使用点符号操纵不同的对象。

我用这个图案以编程方式创建接受键值作为函数变量时嵌套对象属性,如下所示:

const dot = require('dot-object');

function(docid, varname, varvalue){
  let doc = dot.dot({
      [varname]: varvalue 
  });

  Mongo.update({_id:docid},{$set:doc});
}

这种模式让我使用嵌套以及单级属性互换,并干净利落将它们插入到蒙戈。

如果你需要玩的不仅仅是蒙戈JS对象,尤其是在客户端,但有一致性蒙戈工作时,该库为您提供了比前面提到的更多的选择mongo-dot-notation NPM模块。

PS我本来想只提这是一个评论,但显然我的S / O代表是没有高到足以发表评论。 所以,不要试图在SzybkiSasza的评论肌肉,只想强调提供一个替代模块。



Answer 9:

使用$组这样做的过程

.update({"_id": args.dashboardId, "viewData._id": widgetId}, {$set: {"viewData.$.widgetData": widgetDoc.widgetData}})
.exec()
.then(dashboardDoc => {
    return {
        result: dashboardDoc
    };
}); 


Answer 10:

让与财产的名称,包括必要的点路径更新对象。 (“somekey。”从OP的例子+),然后使用该做更新。

//the modification that's requested
updateReq = { 
   param2 : "val2_new",
   param3 : "val3_new"   
}

//build a renamed version of the update request
var update = {};
for(var field in updateReq){
    update["somekey."+field] = updateReq[field];
}

//apply the update without modifying fields not originally in the update
db.collection.update({._id:...},{$set:update},{upsert:true},function(err,result){...});


Answer 11:

    // where clause DBObject
    DBObject query = new BasicDBObject("_id", new ObjectId(id));

    // modifications to be applied
    DBObject update = new BasicDBObject();

    // set new values
    update.put("$set", new BasicDBObject("param2","value2"));

   // update the document
    collection.update(query, update, true, false); //3rd param->upsertFlag, 4th param->updateMultiFlag

如果你有多个字段被更新

        Document doc = new Document();
        doc.put("param2","value2");
        doc.put("param3","value3");
        update.put("$set", doc);


Answer 12:

我试图findAndModify()中预先存在的对象更新的特定字段。

https://docs.mongodb.com/manual/reference/method/db.collection.findAndModify/



Answer 13:

在蒙戈3.6有一个函数mergeObjects究竟做你需要的东西:

https://docs.mongodb.com/manual/reference/operator/aggregation/mergeObjects/



文章来源: How do I partially update an object in MongoDB so the new object will overlay / merge with the existing one