Tuesday, January 13, 2015

Using the Java Driver in MongoDB


The POM File

The POM file contains this dependency:

Getting Started

Navigate to the MongoDB project on Github hereThis link will take you specifically to mongo-java-driver which is documented here.

The sample code for the mongo-java-driver gives examples for performing CRUD operations against MongoDB in a Java environment.

Specifically, the QuickTour.java file contains the examples we need to get up and running.

When learning a new technique, I like to import sample code as a series of test cases to prove my environment.

In this case, I have two VMs configured with Eclipse.  On virtual environment is also running MongoDB; the other is not. I want to see how far each test case will succeed with out an installation of MongoDB.

I'm going to add jUnit to my POM:

and then create this test:
 /* connect to the local database server */  
 MongoClient mongoClient = new MongoClient();  

When I run the test in jUnit, it succeeds.

However, if I run the same test in the Java environment that is configured without MongoDB installed, the same test also works.  So this doesn't prove much, other than the dependencies have been correctly managed by Maven.

I'm going to add the next line from the mongo-java-driver, and I get this:
 /* get handle to "mydb" */  
 DB db = mongoClient.getDB("mydb");  

and here again, both environments (with or without MongoDB), succeed.

The following addition to the test case is more conclusive:
 /* get a list of the collections in this database and print them out */  
 Set<String> collectionNames = db.getCollectionNames();  
 for (final String s : collectionNames) {  

If MongoDB is not installed, this test case will fail with the following stack trace, before reaching any assertion:
 com.mongodb.MongoTimeoutException: Timed out after 10000 ms while waiting for a server that matches AnyServerSelector{}. Client view of cluster state is {type=Unknown, servers=[{address=, type=Unknown, state=Connecting, exception={com.mongodb.MongoException$Network: Exception opening the socket}, caused by {java.net.ConnectException: Connection refused}}]  
      at com.mongodb.BaseCluster.getServer(BaseCluster.java:82)  
      at com.mongodb.DBTCPConnector.getServer(DBTCPConnector.java:650)  
      at com.mongodb.DBTCPConnector.access$300(DBTCPConnector.java:39)  
      at com.mongodb.DBTCPConnector$MyPort.getConnection(DBTCPConnector.java:499)  
      at com.mongodb.DBTCPConnector$MyPort.get(DBTCPConnector.java:447)  
      at com.mongodb.DBTCPConnector.getPrimaryPort(DBTCPConnector.java:406)  
      at com.mongodb.DBApiLayer.isServerVersionAtLeast(DBApiLayer.java:259)  
      at com.mongodb.DBApiLayer.getCollectionNames(DBApiLayer.java:151)  
      at org.swtk.sandbox.mongodb.CreateConnectionTest.createConnection(CreateConnectionTest.java:27)  
      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)  
      at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)  
      at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)  
      at java.lang.reflect.Method.invoke(Method.java:606)  
      at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)  
      at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)  
      at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)  
      at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)  
      at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)  
      at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)  
      at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)  
      at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)  
      at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)  
      at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)  
      at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)  
      at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)  
      at org.junit.runners.ParentRunner.run(ParentRunner.java:363)  
      at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)  
      at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)  
      at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)  
      at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)  
      at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)  
      at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)  

The exception (ConnectionRefused) makes sense.

On the environment that has MongoDB installed, the test case succeeds, and the output from the console is:

Now we've reached a mini-milestone in testing the Java driver configuration for  MongoDB.  We have code that will successfully execute only if:
  1. MongoDB dependencies are correctly managed within the IDE, and
  2. MongoDB itself is correctly installed on the host system

Basic CRUD

If you recall in MongoDB there is a simple concept of a hierarchy: a Collection contains Documents; and a Document contains Fields. Let's start by working with a Collection.

To access a collection, I'm going to use this code:
 /* get a collection object to work with */  
 DBCollection coll = db.getCollection("testCollection");  

This sample code is copied directly from the test client linked above.  To mix things up a little, I type in a different collection name "drwhosaysrun" and the test case still passes.

So the assertion isn't doing much for me. In the JavaDoc for DB.java, I find the documentation for the method.  It doesn't tell me much: "Gets a collection with a given name". 

Fortunately, a posting on Stackoverflow is more revealing.  The method "getCollection" lazily creates a collection.  At this point, all we've done is call the method; and nothing happens.  However, MongoDB returns a reference rather than null.  And if we choose to insert data into the collection, the reference will be instantiated as a collection.

It does appear we could use this technique, if desired:
 boolean collectionExists = db.collectionExists("COLLECTION_NAME");  
 if (collectionExists == false) {  
    db.createCollection("COLLECTION_NAME", null);  

We'll continue with the test client and insert data into the collection:

 /* drop all the data in it */  
 /* make a document and insert it */  
 BasicDBObject doc = new BasicDBObject("name", "MongoDB").append("type", "database").append("count", 1).append("info", new BasicDBObject("x", 203).append("y", 102));  

 /* get it (since it's the only one in there since we dropped the rest earlier on) */  
 DBObject myDoc = coll.findOne();  


And we're good to go.

The test case executes successfully, with the following output:
 { "_id" : { "$oid" : "54b57c0e0cf26d6f2d70a4da"} , "name" : "MongoDB" , "type" : "database" , "count" : 1 , "info" : { "x" : 203 , "y" : 102}}  

Note that because I'm executing the entire test case up to now, the new collection also shows up in the console output for this test case.

No comments:

Post a Comment