By default, Jongo uses Jackson to (un)marshall objects: a no-arg constructor, even private, is enough to write an object into Mongo and read from it.
Note that every Mongo document have an _id field. Defining this field Java side can be done
two ways: the object field can be named _id or annotated with
@JsonProperty("_id"). The object type can be ObjectId – it will be generated
Mongo side – or any Java type, other than array, so long as it is unique.
Careful, saving a document without _id will generate an ObjectId typed field,
even if the Java object define another type for it. So, not choosing ObjectId for
_id field involves always to set it before persisting.
public class Friend {
private ObjectId _id;
}
public class Friend {
@JsonProperty("_id")
private ObjectId key;
}
public class Friend {
// you must generate it!
private String _id;
}
As expected with Jackson, fields are automaticaly mapped to their equivalent json properties (and complex types mapped as sub-properties). No extra annotations needed. For fine grained control over (un)marshalling, refer to Jackson documentation or use your own (un)marshaller.
To handle polymorphism of Java objects, a field containing the class name must be set into the Mongo
document. One can persist a Fox (sub-class of Animal) and manipulate it
as an Animal. This feature is provided out-of-the-box by Jackson. Using another
(un)marshaller implies extra work.
@JsonTypeInfo(use = Id.CLASS, include = As.PROPERTY, property = "_class")
public class Animal {
String gender;
}
public class Fox extends Animal {
boolean wild;
}
Using a singular reserved name, like _class, for this field is a good idea.
Query syntax is almost the same as in Mongo shell: copy/paste, it just works.
Strings have to be escaped with single quotes "{name: 'John'}", numbers don't "{age:
18}".
Iterable<Friend> all = friends.find("{name: 'John'}").as(Friend.class);
Friend john = friends.findOne("{name: 'John'}").as(Friend.class);
Friend john = friends.findOne(new ObjectId("4c...e")).as(Friend.class);
Field names only need quotes when using dot notation "{'address.city': 'London'}".
Queries can be templated: add anchors # as follow friends.find("{name: #, age: #}",
"John", 18)
Binded parameters can be BSON
Primitives or any complex type made of those.
friends.find("{name: #, age: #}", "John", 18); //- will produce {name: 'John', age: 18}
List<String> ages = Lists.newArrayList(22, 63);
friends.find("{age: {$in:#}}", ages); //- will produce {age: {$in:[22,63]}}
Field selection aka. partial loading is not written as in Mongo shell:
Jongo exposes a fields(...) method. A json selector must be provided: {field:
1} to include it, {field: 0} to exclude it.
friends.find("{}").fields("{lastname: 1, address: 1}").as(User.class);
Documents can be sorted in ascending or descending order using a json selector: {field: 1}
for ascending, {field: -1} for descending.
friends.find("{}").sort("{firstname: 1}").as(User.class);
friends.find("{}").sort("{lasttname: -1}").as(User.class);
Behaviour similar to Java driver DBCursor.
friends.find("{}").skip(20).as(User.class);
friends.find("{}").limit(10).as(User.class);
Behaviour similar to Java driver DBCollection.distinct(...).
friends.distinct("address", "", Address.class);
friends.distinct("address", "{name: 'John'}", Address.class);
Behaviour similar to Java driver DBCollection.count(...).
friends.count("{name: 'John'}");
Using Mongo geospacial capacities requires an index and some BSON operators.
friends.ensureIndex("{address: '2d'}");
friends.find("{address: {$near: [0, 0], $maxDistance: 5}}").as(Address.class);
Mongo uses a behind the scenes
syntactic sugar for methods like sort(...), limit(...) and others. The
complete expression can also be used in Jongo.
friends.find("{$query: {}, $maxScan: 2}").as(Friend.class);
friends.find("{$query: {}, $orderby: {name: 1}}").as(Friend.class);
Simply pass an object to the save(...) method, built-in Jackson marshaller will be used to
convert it to json. Object mapping section defines what objects have to look
like.
friends.save(new Friend("Joe", 27));
In early version of Jongo 'upsert' is not available and update is always in 'multi' mode.
friends.update("{name: 'Joe'}", "{$inc: {age: 1}}");
Remove works as if you were in Mongo shell.
friends.remove("{name: 'Joe'}");
Jongo is lighting fast. Not because it is made of ancient wood and magic stones, but because it binds Jackson — the fastest Java json (un)marshalling library — to Mongo Java driver with the slightest glue code possible.
Jongo's performance is currently under our microscope and we already noticed some great improvements over our main competitor: Morphia. Keep tuned.
If one prefers to manually map objects (ie. without a (un)marshaller), he can implements
ResultMapper. Each result entity will be passed to the inherited map(String
json) method.
Iterable<Integer> ages = col.find("{'name':'John'}").map(
new ResultMapper<Integer>() {
@Override
public String map(String json) {
DBObject result = (DBObject) JSON.parse(json);
return result.get("age");
}
}
);
Instead of Jackson, one can provide his own implementation of Marshaller and Unmarshaller.
Marshaller marshaller = new Marshaller() {
@Override
<T> String marshall(T obj) { ... }
};
Unmarshaller unmarshaller = new Unmarshaller() {
@Override
<T> T unmarshall(String json, Class<T> clazz) { ... }
};
Jongo jongo = new Jongo(mongo.getDB("dbname"), marshaller, unmarshaller);
Jongo is deployed into OSS Sonatype (Maven repository hosting service for open source projects).
<dependency>
<groupId>org.jongo</groupId>
<artifactId>jongo</artifactId>
<version>0.1</version>
</dependency>