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. Just name id property _id
or annotate it 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 with a custom _id
type (ie: String, ...) involve 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 automatically 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 Friend
) and manipulate it
as a Friend
. This feature is provided out-of-the-box by Jackson. Using another
(un)marshaller implies extra work.
@JsonTypeInfo(use = Id.CLASS, property = "_class") public class Friend { int age; }
public class Fox extends Friend { String name, color; }
friends.save(new Fox("fantastic", "red-haired")); Friend friend = friends.findOne("{name:'fantastic'}").as(Friend.class); Fox fantastic = (Fox)friend;
Using a singular reserved name, like _class
, for this field is a good idea.
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));
Update syntax is a bit different than in Mongo shell: 'modifier' query has to be passed using with(...)
method.
Upsert and multi options are no longer boolean but flag methods
friends.update("{name: 'Joe'}").with("{$inc: {age: 1}}"); friends.update("{name: 'Joe'}").upsert().multi().with("{$inc: {age: 1}}"); friends.update("{name: 'Joe'}").upsert().with("{$inc: {age: 1}}");
Remove works as if you were in Mongo shell.
friends.remove("{name: 'Joe'}"); friends.remove(new ObjectId("4c...e"));
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'}"
.
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);
Almost all queries in Jongo can be templated: add anchors #
as follow. 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]}}
Behaviour similar to Java driver DBCollection.count(...).
friends.count("{name: 'John'}");
Distinct syntax is almost the same as Find/FindOne operations. Optional query can be setted using query(...)
method
List<String> names = friends.distinct("name").as(String.class);
List<Address> addresses = friends.distinct("address").query("{name: 'John'}").as(Address.class);
This feature will only be available in the Mongo v2.2 release and Jongo already supports it!
Just use a v2.1.0+ (unstable) Mongo server.
All aggregation operators are supported $project, $match, $limit, $skip, $unwind, $group, $sort
and can be piped using and(...)
method
collection.aggregate("{$project:{sender:1}}") .and("{$match:{tags:'read'}}") .and("{$limit:10}") .as(Email.class);
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);
If one prefers to manually map objects (ie. without unmarshaller), he can implements
ResultMapper
. Each result entity will be passed to the inherited map(DBObject result)
method.
Iterable<Integer> ages = col.find("{'name':'John'}").map( new ResultMapper<Integer>() { @Override public Integer map(DBObject result) { //do manual stuff here return result.get("age"); } } );
Instead of Jackson, one can provide his own implementation of Marshaller
and Unmarshaller
.
class CustomMarshaller implements Marshaller { <T> String marshall(T obj) { ... } }; class CustomUnmarshaller implements Unmarshaller { <T> T unmarshall(String json, Class<T> clazz) { ... } }; Jongo jongo = new Jongo(mongo.getDB("dbname"), customMarshaller, customUnmarshaller);
Because Jongo uses Jackson by default, the same objects cannot be exposed with Jersey if they have an ObjectId
. To make Jongo and Jersey work together, use this custom Jackson Provider, it exposes ObjectId
as String
.
If in doubt, this full working sample put everything together.
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.
save()
and update()
can be configured with a WriteConcernsave()
, insert()
, update()
and remove()
return a WriteResult for every callObjectId
is generated Mongo-side, it is setted in the object _id attributeupdate(String, String)
becomes update(String).with(String)
distinct()
returns List<T>
instead of Iterable<T>
find()
and findOne()
Jongo is deployed into OSS Sonatype (Maven repository hosting service for open source projects).
<dependency> <groupId>org.jongo</groupId> <artifactId>jongo</artifactId> <version>0.2</version> </dependency>