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>