0.2 is a deprecated version, please go to main page to get up-to-date documentation

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.

Handling polymorphism

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.

Save

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

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

Remove works as if you were in Mongo shell.

friends.remove("{name: 'Joe'}");
friends.remove(new ObjectId("4c...e"));

Find and FindOne

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

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);

Sorting

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);

Skip and Limit

Behaviour similar to Java driver DBCursor.

friends.find("{}").skip(20).as(User.class);
friends.find("{}").limit(10).as(User.class);

Query templating

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]}}

Count

Behaviour similar to Java driver DBCollection.count(...).

friends.count("{name: 'John'}");

Aggregation

Distinct

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);

New Aggregation Framework

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);

Advanced query

Geospacial indexing

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);

Complete query syntax

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);

Using a custom result mapper

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");
        }
    }
);

Using a custom (un)marshaller

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);

Using Jongo objects with Jersey

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.

Performance

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.

Aggregation Framework
support for the brand new aggregation framework, see querying for more details
WriteConcern
save() and update() can be configured with a WriteConcern
WriteResult
save(), insert(), update() and remove() return a WriteResult for every call
marshalling
move to Jackson 2.0 (no conflict with olders Jackson versions)
save
when an ObjectId is generated Mongo-side, it is setted in the object _id attribute
update
breaking change update(String, String) becomes update(String).with(String)
remove
documents can be removed by id
distinct
to be faithful to the driver, distinct() returns List<T> instead of Iterable<T>
find
query without filter can be writen with empty find() and findOne()

Jongo is deployed into OSS Sonatype (Maven repository hosting service for open source projects).

Add the following dependency to your pom.xml
<dependency>
    <groupId>org.jongo</groupId>
    <artifactId>jongo</artifactId>
    <version>0.2</version>
</dependency>