Status: New
Owner: ----
Labels: Type-Defect Priority-Low
New issue 406 by jaronsampson: UpdateOperations with isolated() do not
honor DatastoreImpl update with createIfMissing behavior
http://code.google.com/p/morphia/issues/detail?id=406
morphia 0.99 / morphia logging 0.99 / morphia validation 0.99
mongo-java-driver-2.7.3 / mongodb-osx-x86_64-2.0.4
The expected upsert behavior using update(query, ops, createIfMissing=true)
fails to work when isolated() is used in the UpdateOperations. Instead the
query always updates existing record after creating an initial record.
Removing isolated() allows this method to be used with the expected upsert
behavior. Also, using findAndModify(query, ops, false, true) upserts
correctly with isolated() left in the ops.
The main difference I can see involves a block in DatastoreImpl, where it
is calling disableValidation on the query used in the update. The
combination of isolated and update seems to result in the query matching
all existing documents in the collection and updating that result set. I
believe I verified this by adding a second document to the collection via
the CLI, and running the morphia update method again: all documents in the
collection ended up with the update calls set operations from my morphia
code.
@SuppressWarnings("rawtypes")
private <T> UpdateResults<T> update(Query<T> query,
UpdateOperations ops, boolean createIfMissing, boolean multi, WriteConcern
wc) {
DBObject u = ((UpdateOpsImpl) ops).getOps();
if (((UpdateOpsImpl) ops).isIsolated()) {
Query<T> q = query.clone();
q.disableValidation().filter("$atomic", true);
return update(q, u, createIfMissing, multi, wc);
}
return update(query, u, createIfMissing, multi, wc);
}
compared to this block:
public <T> T findAndModify(Query<T> query, UpdateOperations<T> ops,
boolean oldVersion, boolean createIfMissing) {
QueryImpl<T> qi = (QueryImpl<T>) query;
DBCollection dbColl = qi.getCollection();
//TODO remove this after testing.
if(dbColl == null)
dbColl = getCollection(qi.getEntityClass());
if (log.isTraceEnabled())
log.info("Executing findAndModify(" +
dbColl.getName() + ") with update ");
DBObject res = dbColl.findAndModify(qi.getQueryObject(),
qi.getFieldsObject(),
qi.getSortObject(),
false,
((UpdateOpsImpl<T>)
ops).getOps(), !oldVersion,
createIfMissing);
if (res == null)
return null;
else
return (T) mapr.fromDBObject(qi.getEntityClass(),
res, createCache());
}
...which sends the UpdateOperations from UpdateOpsImpl settings up to the
driver without changing the QueryImpl fields through disableValidation().
Note: I have not stress tested this to see if either method actually
isolates the update operation or not.
Thanks,
Jaron Sampson
Attachments:
morphia.issuereport.createIfMissing.isolated.txt 4.7 KB