给定此文档保存在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客户端,但是任何示例都将受到欢迎


当前回答

最好的解决方案是从对象中提取属性,并使它们成为平面点表示法键值对。例如,你可以使用这个库:

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

它有.flatten函数,允许您将对象更改为平坦的属性集,然后可以给$set修饰符,而不用担心您现有DB对象的任何属性将被删除/覆盖而不需要。

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

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

其他回答

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

您可以在基于聚合的更新中使用$mergeObjects。类似的

db.collection.update(
   { _id:...},
   [{"$set":{
      "some_key":{
        "$mergeObjects":[
          "$some_key",
          new info or { param2 : "val2_new", param3 : "val3_new"}
       ]
      }
   }}]
)

这里有更多的例子

我尝试了findmodify()来更新一个预先存在的对象中的特定字段。

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

你可以做一个upsert,这个操作在MongoDB是用来保存文档到集合。 如果文档符合查询条件,则执行更新操作,否则将向集合中插入新文档。

类似如下所示

db.employees.update(
    {type:"FT"},
    {$set:{salary:200000}},
    {upsert : true}
 )

我用自己的函数解出来了。如果你想更新文档中的指定字段,你需要清楚地解决它。

例子:

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