What is the correct method to update a document while using Mongo Cursor?

3k views Asked by At

I am trying to update a document in Mongo DB using cursor. My Mongo DB Java driver version is 3.3.0. Following is my code snippet.

MongoCollection<Document> collection = mongoDb.getCollection("customer");
MongoCursor<Document> cursor = collection.find().iterator();
try{
    while(cursor.hasNext()){
        Document oldDoc = cursor.next();
        //created new Document newDoc
        collection.replaceOne(oldDoc, newDoc);
    }
}catch(Exception e){
    e.printStackTrace();
}

Though this way, I can update the document, I think this is not the efficient way because here collection is being searched 2 times. I want to update the old document with some values and later on want to save it using some methods like collection.update(oldDoc) or collection.save(oldDoc) without creating a new document. I searched and came across the following post.

Java, MongoDB: How to update every object while iterating a huge collection?

This is exactly what I want, but I don't find save() method in the new API. So I have 3 questions here.

  1. What is equivalent of save() method in Mongo DB Java driver 3.3.0 API through which I can update or save a document while iterating a cursor?
  2. Is there anyway by which I can update the existing document without creating a new document in Mongo DB Java driver 3.3.0 API?
  3. Above link shows save() was part of Mongo DB Java driver API earlier. Any expert answer, why it got dropped from API?
1

There are 1 answers

4
Gerald Mücke On

Don't worry about the additional search, the replaceOne method's first parameter is a filter. Using the old doc as filter will use the _id property of the document which should be relatively fast. So basically, the way you do it, is correct. But bear in mind that the operation is non-transactional, which means the update may affect the cursor's result set. So it could happen, that the updated document will be stored at a positions the cursor has not yet passed, resulting in the document being processed twice.

Regarding your questions.

  1. The semantics of save method in mongo shell is to update or insert the document if not yet existing (aka upsert). The closest thing to that on the MongoCollection is updateOne() with an UpdateOptions upsert set to true. That's basically what the save command does. But replaceOne leads to the same result, if the replacement document is a modified version of the original one.

  2. Why worrying about object creation? In java it comes at next to no cost and don't worry about GC or Memory consumption as those shortlived objects are GC'ed pretty fast. If you want to have code more concise you may create a dedicated filter object with just the _id of the oldDoc, modify the oldDoc and use it instead of the new Doc.

For example:

UpdateOptions upsert = new UpdateOptions().upsert(true);
Bson idFilter = Filters.eq("_id", oldDoc.getObjectId("_id"));
//modify the oldDoc
oldDoc. ...
collection.replaceOne(idFilter, oldDoc, upsert);