How do I update fields of documents in mongo db us

2019-01-18 09:50发布

问题:

References:

  • http://www.mongodb.org/display/DOCS/Java+Tutorial

Still pretty new to mongo db but I'm trying to update part of an existing document inside a collection... unfortunately, the link above doesn't have an update example.

Essentially, i just want to be able to:

  1. Add new fields to a document
  2. Update existing fields of a document to a new value

Here's my code (Grails + Groovy + Java + MongoDB + the java driver):

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

This pretty much clobbers the entire object... I might try just modifying the original shape object and then running the update on that. But until then, does anyone have experience updating just individual fields (rather than the entire document)?

EDIT:

I just tried it and was able to successfully update by sending the entire object across with new and/or updated fields and that works. I wonder if the driver is smart enough to only update the smallest subset of changes or if it's just blindly updating the entire thing? (In the case below, is it just updating the foo field across the wire or the entire shape document?)

Code:

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

回答1:

I wonder if the driver is smart enough to only update the smallest subset of changes or if it's just blindly updating the entire thing?

No, if you use the "normal" update method, the whole object will be sent over the wire. I suspect that the database server itself will be clever enough to only update the necessary indexes (and not the ones that did not change), if possible (i.e. the object could be updated in place and did not have to be moved because it grew too much)

What you can do is use the "atomic update modifier" functions. The Java documentation is a bit light on them, but since the driver just transmits the JSON, the stuff from the non-Java tutorials should work, for example:

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


回答2:

Found an example here, which seems to show the usage for the update call. So for your example, I believe something like this should work?

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

Edit

You might be able to use a category to construct your BasicDBObjects in a more groovy way...

Something like this might do it:

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() )
}

I haven't tested this though...

Edit 2

Actually, BasicDBObject is a Map, so you should be able to do:

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

without needing the builder



回答3:

A lot of the answers on this post are using older versions of the Mongo Java Driver. If you're using a newer version of the Java Driver (v3.0+) then the preferred method seems to be to use the Document object instead of the DBObject interface.

Here is an example:

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


回答4:

This answer uses the mongo shell, but shows how you can go deep into a JSON object structure to modify a specific field without overwriting the rest.

Given the JSON object in a collection called 'my_collection':

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

To update 'var_b' , without overwriting anything else:

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

To update the 3rd element in the array 'list' with value '99', without overwriting anything else:

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

Just use the above steps . You can change the details without affecting other items associated to the same key.



回答6:

// update

WriteResult usr = (WriteResult)mongoOperation.upsert(new  Query(Criteria.where("name").is("till")),  

Update.update("password", "jk45"), "collection");

System.out.println("updatedUser : " + usr );