How to use Morphia's update(...) method with a QueryDSL query?

108 views
Skip to first unread message

Andreas Oberhoff

unread,
Feb 11, 2015, 1:21:12 PM2/11/15
to quer...@googlegroups.com
Hello,

in Morphia, using update(...) methods goes like this:

Morphia morphia = new Morphia();
Datastore datastore = morphia.createDatastore("MorphiaSampleDb");
Hotel hotel = new Hotel("Fairmont", 3, new Address("1 Rideau Street", "Ottawa", "K1N8S7", "Canada"));
datastore
.save(hotel);

Query<Hotel> updateQuery = datastore.createQuery(Hotel.class).field("_id").equal(hotel.getId());
UpdateOperations<Hotel> datastore.createUpdateOperations(Hotel.class).set("name", "Fairmont Chateau Laurier");
datastore
.update(updateQuery, ops);

Problem here is the updateQuery object which is not a type safe QueryDSL query.

Is there an option converting a QueryDSL query to a Morphia query or any other trick of solving this problem? Maybe its a missing feature...

Best regards,
Andreas

timowest

unread,
Feb 12, 2015, 11:07:25 AM2/12/15
to quer...@googlegroups.com
Hi Andreas.

This is currently not supported. But contributions are welcome.

Timo

Andreas

unread,
Feb 21, 2015, 12:00:48 PM2/21/15
to quer...@googlegroups.com
I wrote a quick and dirty workaround for this:

QHotel qHotel = QHotel.hotel;
MorphiaQuery<Hotel> query = new MorphiaQuery<Hotel>(morphia, datastore, qHotel);
query
.where(qHotel.id.eq(hotel.getId());
 
Query<Hotel> q = createMorphiaQuery(Hotel.class, query, datastore);
UpdateOperations<Hotel> ops = datastore.createUpdateOperations(Hotel.class).set(field(qHotel.name), "New Name");

datastore
.update(q, ops);


The helper methods:

private <T> Query<T> createMorphiaQuery(Class<T> kind, MorphiaQuery<T> query, Datastore datastore)
     
throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException,
     
InvocationTargetException {
 
Query<T> q = datastore.createQuery(kind);
 
DBObject o = (DBObject) JSON.parse(query.toString());
 
Method m = q.getClass().getMethod("setQueryObject", DBObject.class);
 m
.invoke(q, o);
 
return q;
}

private String field(StringPath path) {
 
String field = path.toString();
 
return field.substring(field.indexOf(".") + 1);
}


Now updating with Morphia and QueryDSL in a type safe manner is no problem anymore.

Best regards,
Andreas

timowest

unread,
Feb 24, 2015, 2:39:09 PM2/24/15
to quer...@googlegroups.com
Hi Andreas.

Thanks for the code samples.

Timo

Gaspard Petit

unread,
Feb 13, 2016, 4:48:42 AM2/13/16
to Querydsl
Hello,

I initially implemented my solution based on Andreas answer.  Although the createMorphiaQuery hack scares me, it works fine.  The Update however was slightly more tricky - it worked in most simple cases but failed on others.  For example, if your object contains a map and you do q.someMap.get("aKey").something, you will end up with a field value of "someMap.get(aKey).something" instead of "someMap.aKey.something".

You can easily get a stronger QueryDSL Path -> Mongo Path using the MorphiaSerializer that is part of QueryDSL.  It works like this:

MorphiaSerializer serializer = new MorphiaSerializer(morphia);
String field = serializer.visit(path, null);

Gaspard

Gaspard Petit

unread,
Apr 20, 2016, 4:20:40 AM4/20/16
to Querydsl
Update to the thread - Timo has updated the AbstractMongoDbQuery in QueryDSL so we can now extract the DBObject (see https://github.com/querydsl/querydsl/pull/1851/commits/a9d96c7ee17bb1df8e3ee6bfda699b3fba92d806).

In the code posted by Andreas, instead of 

Query<T> q = datastore.createQuery(kind);
DBObject o = (DBObject) JSON.parse(query.toString());

One can now write

Query<T> q = datastore.createQuery(kind);
DBObject o = query.asDBObject();

Thus saving unnecessary serialization-deserialization.
Reply all
Reply to author
Forward
0 new messages