[JAVA-798] DeepCopy ObjectId causes an indefinite Insert() instead of Upsert() in the Save() method. Created: 29/Mar/13  Updated: 31/Mar/15  Resolved: 25/Jun/13

Status: Closed
Project: Java Driver
Component/s: API
Affects Version/s: 2.9.2, 2.9.3
Fix Version/s: 3.0.0

Type: Bug Priority: Critical - P2
Reporter: Daniel Marcotte Assignee: Unassigned
Resolution: Done Votes: 0
Labels: DeepCopy, ObjectId, Save, Upsert
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified


 Description   

Hello

I use a DeepCopy library (https://code.google.com/p/cloning/) in my application to speed-up tremendous amount of pre-constructed objects with a deep hierarchy. However, the ObjectId class really doesn't react well to this behavior.

If I create a "new ObjectId()", the flag "_new" is set to "true". If I store, let's say in a HashMap, my Object containing this Id and I try to SAVE() my object it works for the first time. However, the second time I SAVE() my object using your driver, MongoDB tells me that there's a violation of the Index.

Looking at your source code :

/**

  • Saves an object to this collection (does insert or update based on the object _id).
  • @param jo the <code>DBObject</code> to save
  • @param concern the write concern
  • @return
  • @throws MongoException
    */
    public WriteResult save( DBObject jo, WriteConcern concern ){
    if ( checkReadOnly( true ) )
    return null;

_checkObject( jo , false , false );

Object id = jo.get( "_id" );

if ( id == null || ( id instanceof ObjectId && ((ObjectId)id).isNew() ) )

{ if ( id != null && id instanceof ObjectId ) ((ObjectId)id).notNew(); if ( concern == null ) return insert( jo ); else return insert( jo, concern ); }

DBObject q = new BasicDBObject();
q.put( "_id" , id );
if ( concern == null )
return update( q , jo , true , false );
else
return update( q , jo , true , false , concern );

}

It Looks like since the ObjectId is DeepCopied, the Driver always do an "Insert" instead of an Update : Upsert = True. Shouldn't the "save" method always process to a Upsert instead of a Insert / Update?

I managed a workaround setting my ObjectId to notNew() everytime I create one and "everything" seems to work fine now, the driver doing an Update (Upsert:true).

My Questions : Why do you Insert if the Upsert command works fine? Is there any performance Issue I should be aware of using this "trick"? Will MongoDB handle Upsert poorly compared to "real" inserts?



 Comments   
Comment by Jeffrey Yemin [ 31/Mar/15 ]

Closing all resolved 3.0.0 issues, as 3.0.0 has been tagged and released.

Comment by Jeffrey Yemin [ 25/Jun/13 ]

Fixed in https://github.com/mongodb/mongo-java-driver/commit/aa4b4355c808e045ce00cc1dfbdd0bf78fb6901a

Comment by Jeffrey Yemin [ 30/Mar/13 ]

I'll have to check, but I would think that it would be minimal.

Comment by Daniel Marcotte [ 29/Mar/13 ]

Thanks, a Stateless ObjectId will definitely help for Serialization/Deserialization purpose other than with the MongoDB Java Driver.

Is there any performance cost within MongoDB for Insert vs Update (Upsert:true)?

Comment by Jeffrey Yemin [ 29/Mar/13 ]

I'm not a fan of isNew() either. I plan to remove it in 3.0 and make ObjectId immutable.

Generated at Thu Feb 08 08:53:06 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.