【问题标题】:How do I update fields of documents in mongo db using the java driver?如何使用 java 驱动程序更新 mongo db 中的文档字段?
【发布时间】:2011-04-04 13:51:46
【问题描述】:

参考资料:

对于 mongo db 来说仍然很新,但我正在尝试更新集合中现有文档的一部分......不幸的是,上面的链接没有更新示例。

基本上,我只是希望能够:

  1. 向文档添加新字段
  2. 更新文档的现有字段 到一个新的值

这是我的代码(Grails + Groovy + Java + MongoDB + java 驱动程序):

def shape = mongo.shapes.findOne(new BasicDBObject("data", "http://www.foo.com")); // get the document
mongo.shapes.update(new BasicDBObject("_id", shape._id), new BasicDBObject("isProcessed", 0));  // add a new "isProcessed" field set to 0
mongo.shapes.update(new BasicDBObject("_id", shape._id), new BasicDBObject("data", "http://www.bar.com"));

这几乎破坏了整个对象...我可能会尝试仅修改原始形状对象,然后对其运行更新。但在那之前,有没有人只更新个别字段(而不是整个文档)?

编辑:

我刚刚尝试过,并且能够通过发送带有新和/或更新字段的整个对象来成功更新,这很有效。我想知道驱动程序是否足够聪明,只能更新最小的更改子集,还是只是盲目地更新整个内容? (在下面的例子中,它只是通过网络更新 foo 字段还是整个 shape 文档?)

代码:

def shape = mongo.shapes.findOne(); // get the first shape to use as a base
shape.removeField("_id");  // remove the id field
shape.put("foo","bar");  // add a new field "foo"
mongo.shapes.insert(shape);  // insert the new shape
def shape2 = mongo.shapes.findOne(new BasicDBObject("foo", "bar"));  // get the newly inserted shape (and more importantly, it's id)
shape2.put("foo", "bat");  // update the "foo" field to a new value
mongo.shapes.update(new BasicDBObject("_id", shape2._id), shape2);  // update the existing document in mongo

【问题讨论】:

    标签: java mongodb grails groovy mongo-java


    【解决方案1】:

    我想知道驱动程序是否足够聪明,只能更新最小的更改子集,还是只是盲目地更新整个内容?

    不,如果您使用“正常”更新方法,整个对象将通过网络发送。 我怀疑数据库服务器本身将足够聪明,只更新必要的索引(而不是那些没有改变的索引),如果可能的话(即对象可以就地更新并且不必移动,因为它也增长了很多)

    您可以做的是使用“原子更新修饰符”功能。 Java 文档对它们有点轻描淡写,但由于驱动程序只是传输 JSON,因此非 Java 教程中的内容应该可以工作,例如:

    shapes.update((DBObject)JSON.parse(    "{ 'foo' : 'bar'}"),  
        (DBObject) JSON.parse(          "{ '$set' : { 'foo': 'bat'}}")   );
    

    【讨论】:

    • 谢谢!我想我更喜欢这段代码,因为它比标准语法更清晰......我会试试看。
    • 我试过了,但无法解析。它不喜欢单引号,然后第二个 JSON.parse 不能转换为 DBObject(它是一个 HashMap)。
    • @Gandalf:抱歉,未经测试的代码。但是应该和上面的很相似。
    【解决方案2】:

    找到an example here,这似乎显示了更新调用的用法。所以对于你的例子,我相信这样的事情应该有效吗?

    // Find an object
    def shape2 = mongo.shapes.findOne( new BasicDBObject( 'foo', 'bar' ) )
    // And update the foo field from 'bar' to 'bat'
    mongo.shapes.update( shape2, new BasicDBObject( '$set', new BasicDBObject( 'foo', 'bat' ) ) )
    

    编辑

    您也许可以使用一个类别以一种更时髦的方式构造您的 BasicDBObjects...

    这样的事情可能会做到:

    class BasicDBObjectMapBuilder {
      static String toDbObj( String s ) { s }
      static BasicDBObject toDbObj( Map m ) {
        m.inject( null ) { r, it -> new BasicDBObject( it.key, it.value.toDbObj() ) }
      }
    }
    
    use( BasicDBObjectMapBuilder ) {
      def shape2 = mongo.shapes.findOne( new BasicDBObject( 'foo', 'bar' ) )
      // And update the foo field from 'bar' to 'bat'
      mongo.shapes.update( shape2, [ '$set':[ 'foo', 'bat' ] ].toDbObj() )
    }
    

    不过我还没有测试过...

    编辑 2

    其实BasicDBObject就是一个Map,所以你应该可以做到:

      mongo.shapes.update( shape2, [ '$set':[ 'foo', 'bat' ] ] as BasicDBObject )
    

    无需构建器

    【讨论】:

    • 我的眼睛!他们烧了!非常感谢你,这现在完全有道理了......他们让我们为此编写的代码太丑陋了! :)
    • 哈哈哈......是的......我已经粗略地尝试了一个类别来从地图中构建 DBObjects 作为编辑......没有测试它......
    • 是的,Java 让使用 JSON 变得丑陋。 Java 驱动程序应该提供传递 JSON 字符串的方法(但这也受到 Java 中缺少多行字符串和备用引号字符的阻碍),以及一些具有有意义名称的构建器方法(因此您不必键入 $set )。
    【解决方案3】:

    这篇文章中的很多答案都是使用旧版本的 Mongo Java 驱动程序。如果您使用的是较新版本的 Java 驱动程序 (v3.0+),那么首选方法似乎是使用 Document 对象而不是 DBObject 接口。

    这是一个例子:

    MongoClient client = new MongoClient();
    MongoCollection<Document> fooCollection = client.getDatabase("test").getCollection("foo");
    
    Bson filter = Filters.eq("_id", "123d45678c467bb433c99f99");
    Bson updates = Updates.set("isFoo", true);
    fooCollection.findOneAndUpdate(filter, updates);
    

    【讨论】:

    • 我试过你的方法,但它不适用于 MongoDB Java Driver 3.2。
    【解决方案4】:

    此答案使用 mongo shell,但展示了如何深入 JSON 对象结构以修改特定字段而不覆盖其余字段。

    给定名为“my_collection”的集合中的 JSON 对象:

    { 
      "_id" : ObjectId("50fdb2a73f7bc7a5acecc4f8"), 
      "data" : { 
        "list" : [ 0, 1, 2, 7, 4, 5 ], 
        "subobj" : { 
           "var_a":"valuea",
           "var_b":"valueb" 
         }
      }
    }
    

    要更新 'var_b' ,而不覆盖其他任何内容:

    db.my_collection.update({"_id":"50fdb2a73f7bc7a5acecc4f8"}, { "$set":{"data.subobj.var_b":"new_value"}})
    

    用值 '99' 更新数组 'list' 中的第三个元素,而不覆盖其他任何内容:

    db.my_collection.update({"_id":"50fdb2a73f7bc7a5acecc4f8"}, { "$set":{"data.list.2":"99"} } )
    

    【讨论】:

      【解决方案5】:
      DBCollection dbCollection = db.getCollection("mycollection");
      BasicDBObject dbObject = new BasicDBObject();
      dbObject.put("_id", "3"); 
      // your update condition - or the query
      DBObject newObject =  dbCollection.find(dbObject).toArray().get(0);
      // I just take the first element. Can iterate through as per your requirement if multiple fields        exist
      newObject.put("key","value");
      //add field, either a new field or any existing field
      dbCollection.findAndModify(dbObject, newObject);
      

      只需使用上述步骤。您可以更改详细信息,而不会影响与同一键关联的其他项目。

      【讨论】:

        【解决方案6】:

        //更新

        WriteResult usr = (WriteResult)mongoOperation.upsert(new  Query(Criteria.where("name").is("till")),  
        
        Update.update("password", "jk45"), "collection");
        
        System.out.println("updatedUser : " + usr );
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多