Enterprise Java

Creating a MongoDB Capped Collection in Java

In MongoDB, it’s possible to preserve the insertion order of documents into a collection in a circular fashion. These types of collections are called Capped Collections in MongoDB. The MongoDB documentation describes Capped Collections:

“Capped collections are fixed-size collections that support high-throughput operations that insert, retrieve, and delete documents based on insertion order. Capped collections work in a way similar to circular buffers: once a collection fills its allocated space, it makes room for new documents by overwriting the oldest documents in the collection.”

OK, so we know what a capped collection is, but how to we create one?

From the MongoDB shell, we would create a capped collection using thedb.createCollection command:

db.createCollection("logs", {capped: true,
                             size: 4096,
                             max:5})

This command tells MongoDB to create a collection called “logs” with a maximum size of 4096 bytes which can hold a maximum of 5 documents. When the 6th document is added, the first document is removed form the collection ensuring that there is only ever a maximum of 5 documents in the collection. The “size” parameter is mandatory, however the “max” parameter is optional.

In Java, there are two common ways to communicate with MongoDB; the MongoDB Java Driver and with Morphia (the lightweight type-safe mapping library for mapping Java objects to/from MongoDB).

First, let’s first look at using the Java Driver.

Java Driver

With the Java Driver, again, we use the db.createCollection command, this time passing a BasicDBObject as the parameter. This parameter has the fields “capped”, “size” and “max” which specify that the collection is capped, the maximum size of the collection in bytes and the maximum number of entries in the collection. The following code snippet shows how to connect to a local instance of MongoDB and create a capped collection.

MongoClient mongoClient = new MongoClient(new MongoClientURI("mongodb://localhost"));
DB db = mongoClient.getDB("test");

DBCollection collection;
if (!db.collectionExists("cappedLogsJavaDriver")) {
    BasicDBObject options = new BasicDBObject("capped", true);
    options.append("size", 4096);
    options.append("max", 5);
    collection = db.createCollection("cappedLogsJavaDriver", options);
} else {
    collection = db.getCollection("cappedLogsJavaDriver");
}

Once we’ve created a collection, we can insert documents into it to ensure that it is working as expected. The following code snippet shows how to insert 8 documents into the collection (remember, only the last 5 of these will be stored as it’s a capped collection).

for (int i = 0; i < 8; i++) {
    BasicDBObject logEntry = new BasicDBObject("logId", i);
    collection.insert(logEntry);
}

Using the MongoDB interactive shell, we can verify the documents that are now stored in the collection are as expected.

> db.cappedLogsJavaDriver.find()
{ "_id" : ObjectId("54a1ca44a82617da4f72e025"), "logId" : 3 }
{ "_id" : ObjectId("54a1ca44a82617da4f72e026"), "logId" : 4 }
{ "_id" : ObjectId("54a1ca44a82617da4f72e027"), "logId" : 5 }
{ "_id" : ObjectId("54a1ca44a82617da4f72e028"), "logId" : 6 }
{ "_id" : ObjectId("54a1ca44a82617da4f72e029"), "logId" : 7 }

Morphia

Now that we’ve seen how to create a collection via the Java Driver, let’s see how we can accomplish the same thing by using Morphia.

The essence of Morphia is to map Java classes to/from MongoDB. Classes that we wish to persist in MongoDB are annotated with the @Entity annotation, which are then stored within a collection usually named after the class being annotated. To create a capped collection, we must add additional values onto the @Entity annotation to specify the maximum number of entries in the collection and the size of the collection. Modelling the same type of object as used in the example for the Java Driver, we would create a LogEntry class as follows:

@Entity(value="cappedLogsMorphia", cap=@CappedAt(count=5, value=4096))
public class LogEntry {

    private int logId;

    @Id
    private ObjectId id;

    public LogEntry(int logId) {
        this.logId = logId;
    }

    public int getLogId() {
        return logId;
    }

    public void setLogId(int logId) {
        this.logId = logId;
    }
}

We can see that this class is annotated with @Entity specifying that the collection should be capped with a maximum of 5 documents and a size of 4096 bytes.

With Morphia, the capped collection is created at start-up time by invoking the .ensureCaps() method on the Morphia Datastore as shown below.

MongoClient mongoClient = new MongoClient(new MongoClientURI("mongodb://localhost"));
DB db = mongoClient.getDB("test");

Morphia morphia = new Morphia();
morphia.map(LogEntry.class);

Datastore datastore = morphia.createDatastore(mongoClient, "test");
datastore.ensureCaps();

Again, as before, we can insert 8 documents into the collection to verify that only the last 5 are stored.

for (int i = 0; i < 8; i++) {
    LogEntry logEntry = new LogEntry(i);
    datastore.save(logEntry);
}
> db.cappedLogsMorphia.find()
{ "_id" : ObjectId("54a1ce9da82629642c64f5d9"), "className" : "com.davidsalter.cappedcollection.LogEntry", "logId" : 3 }
{ "_id" : ObjectId("54a1ce9da82629642c64f5da"), "className" : "com.davidsalter.cappedcollection.LogEntry", "logId" : 4 }
{ "_id" : ObjectId("54a1ce9da82629642c64f5db"), "className" : "com.davidsalter.cappedcollection.LogEntry", "logId" : 5 }
{ "_id" : ObjectId("54a1ce9da82629642c64f5dc"), "className" : "com.davidsalter.cappedcollection.LogEntry", "logId" : 6 }
{ "_id" : ObjectId("54a1ce9da82629642c64f5dd"), "className" : "com.davidsalter.cappedcollection.LogEntry", "logId" : 7 }

Checking a collection status

Once we’ve created a capped collection in MongoDB, we can check its status by executing the .stats() method on the collection from within the Mongo DB interactive shell.

> db.cappedLogsJavaDriver.stats()
{
    "ns" : "test.cappedLogsJavaDriver",
    "count" : 5,
    "size" : 180,
    "avgObjSize" : 36,
    "storageSize" : 4096,
    "numExtents" : 1,
    "nindexes" : 1,
    "lastExtentSize" : 4096,
    "paddingFactor" : 1,
    "systemFlags" : 1,
    "userFlags" : 0,
    "totalIndexSize" : 8176,
    "indexSizes" : {
        "_id_" : 8176
    },
    "capped" : true,
    "max" : 5,
    "ok" : 1
}

Here we can see that the collection is indeed capped (“capped”=true) and that the maximum number of entries in the collection is 5 (“max”=5).

  • The source code for the examp[les using in this post can be found at GitHub.

David Salter

David is a software developer who has been developing software professionally since 1991. He started programming in Java way back with Java 1.0 developing desktop applications and applets. Since 2001 he has been developing enterprise and web applications using both Java standards and open source solutions. David is the author of "NetBeans IDE 8 Cookbook", "Building SOA-Based Composite Applications using NetBeans 6" and "Seam 2.x Web Development”.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button