For enquiries call:

Phone

+1-469-442-0620

April flash sale-mobile

HomeBlogWeb DevelopmentGetting Started with MongoDB and Java

Getting Started with MongoDB and Java

Published
05th Sep, 2023
Views
view count loader
Read it in
10 Mins
In this article
    Getting Started with MongoDB and Java

    MongoDB is being used extensively across several high-performing apps all around the world. In this article, we gain a thorough understanding of how to interact with MongoDB using Java Drivers and explore the different functionalities and features that can be used.

    What is MongoDB?

    MongoDB commonly referred to as just “Mongo” is a NoSQL document-based database that is used to store and organize data without using a relational table or columnar format.

    MongoDB adopts a JSON-like structure to persist data, and a single such entity is called a document. If you’d like to derive a similarity from the relational database world, in most cases one could consider a document in NoSQL terminology to mean the same thing as a record in a SQL DB. A group of these documents is called a collection.

    Why Use MongoDB?

    Mongo forms the persistent entity in the MERN stack. It is an extremely useful database to work with when it is difficult or impossible to predict the schema of data to be stored in the database by an application.

    Since Mongo also does not have the overhead to maintain tabular relations, it has an edge in performance over its SQL counterparts.

    Setting up MongoDB

    The MongoDB installation document which is available at docs.mongodb.com has step-by-step instructions to install MongoDB locally on your system for various popular operating systems. If you’d like to save all the hassle of installing things on your system and just get started working with Mongo, you could also explore the free tier of MongoDB Atlas by registering on their portal available at mongodb.com.

    The Mongo Java Driver

    To interact with MongoDB from our Java application, we will use a piece of software called the Java Driver, which is an official and recommended MongoDB driver application for the Java language.

    If you are using a different programming language, you would need to use the specific driver for that language of your choice. Mongo provides official drivers for the most commonly used programming languages.

    The driver exposes certain APIs which makes working with the database much easier and simplifies the interaction between the business logic and the data store in our applications.

    A highly simplified illustration depicting the role of the driver in an application is as follows:

    The Mongo Java Driver

    Using the Mongo Java Driver

    Let’s create some example snippets to demonstrate CRUD operations in a Java application, using the Java driver. But before we dive into writing our code to manipulate data, let’s first add the MongoDB driver dependency to our project.

    In our example, we are going to use Maven to build our project. So let’s add the following dependency in the `pom.xml` file, which could be found in the project’s root directory:

    <dependencies>
       <dependency>
           <groupId>org.mongodb</groupId>
           <artifactId>mongodb-driver-sync</artifactId>
           <version>4.4.0</version>
       </dependency>
    </dependencies>

    At the time of writing this article, the latest driver version was 4.4.0. Feel free to change this as per the latest version at the time when you are reading this. Also make sure to read the driver’s documentation if the version you would be using is different from the one described here.

    Now, let’s create a singleton connector class named `MongoConnector.java` under the same directory where the `Main` class file resides (in this example the path is `src/main/java/ MongoConnector.java`), to centralize the database connection and its related logic and expose some methods for our application to consume:

    import com.mongodb.client.MongoClient;
    import com.mongodb.client.MongoClients;
    import org.bson.Document;
     
    import java.util.ArrayList;
    import java.util.List;
     
    public class MongoConnector {
     
       private static MongoClient instance = null;
     
       public MongoConnector(String dbUri) throws InstantiationException {
           if(instance == null) {
               instance = MongoClients.create(dbUri);
           }else{
               throw new InstantiationException("Connector Instance Already Exists");
           }
       }
     
       public MongoClient getInstance() {
           return instance;
       }
     
       public void listDatabases(){
           try {
               List<Document> databases = instance.listDatabases().into(new ArrayList<>());
               databases.forEach(db -> System.out.println(db.get("name")));
           } catch(Exception err){
               System.out.println(err.getMessage());
           }
       }
    }

    For now, we have a method to get the connection instance and another one to list the database names.

    To test if the driver is integrated successfully into the project and is working as expected, from our `Main` class, let’s pull the list of database names in the local Mongo instance:

    public class Main {
       public static void main(String args[]){
           try{
               MongoConnector dbConnection = new MongoConnector("mongodb://localhost:27017");
               dbConnection.listDatabases();
           }catch(InstantiationException error){
               System.out.println(error.getMessage());
           }
       }
    }

    When we compile (Press `crtl+F9` in intelliJ) and run (`shift+F10`) this project, we’ll see the list of database names printed on the console, indicating that the driver integration and the database connection works as expected.

    Using the Mongo Java Driver

    Thus we have set up the driver successfully. Now, let’s look at some ways to read and write data from our application.

    Create a Database with a Collection:

    In this section and the following ones, we will be looking at performing CRUD (Create Read Update Delete) operation from our application code on a Mongo database.

    Let’s assume that we’d want to maintain a menu for a restaurant in our database

    We’ll extend our connector class with the following methods so that we could programmatically create a database and a collection from our code:

    public MongoDatabase createDB(String dbName){ 
       return instance.getDatabase(dbName); 
    } 
      
    public void createCollection(MongoDatabase db, String collectionName){ 
       db.createCollection(collectionName); 
    } 
      
    public void printCollectionNames(MongoDatabase db){ 
       List<String> collections = db.listCollectionNames().into(new ArrayList<>()); 
       collections.forEach(name -> System.out.println(name));

    The `getDatabase` method will create a new database if the specified database is not present.

    Now we’ll modify the Main class code to use the connector methods for creating a restaurant database with a menu collection, programmatically:

    import com.mongodb.client.MongoDatabase;
     
    public class Main {
       public static void main(String args[]){
           try{
               MongoConnector dbInstance = new MongoConnector("mongodb://localhost:27017");
               MongoDatabase restaurantDB =  dbInstance.createDB("restaurant");
               dbInstance.createCollection(restaurantDB,"menu");
               dbInstance.listDatabases();
               System.out.println("***********");
               dbInstance.printCollectionNames(restaurantDB);
     
           }catch(InstantiationException error){
               System.out.println(error.getMessage());
           }
       }
    }

    Insert A Document:

    We can modify the main class as follows to insert a single document:

    import com.mongodb.client.MongoClient;
    import com.mongodb.client.MongoCollection;
    import org.bson.Document;
     
     
    public class Main {
       public static void main(String args[]){
           try{
               MongoClient dbInstance = new MongoConnector("mongodb://localhost:27017").getInstance();
               MongoCollection menu = dbInstance.getDatabase("restaurant").getCollection("menu");
               menu.insertOne(new Document("name","Test Item 1").append("price",120.50));
           }catch(InstantiationException error){
               System.out.println(error.getMessage());
           }
       }
    }

    When we compile and run this code, a new document will be inserted into the menu collection in the restaurant’s database.

    We can also verify that from the mongo shell as follows:

    Using the Mongo Java Driver

    When the _id is not provided, the driver automatically adds it during insertion.

    Insert Many Documents:

    We could also perform multiple insertions at once programmatically using the `insertMany` method on the collection. 

    The code snippet to demonstrate `insertMany` is as follows:

    import com.mongodb.client.MongoClient; 
    import com.mongodb.client.MongoCollection; 
    import org.bson.Document; 
      
    import java.util.ArrayList; 
    import java.util.List; 
    import java.util.Random; 
      
      
    public class Main { 
       public static void main(String args[]){ 
           try{ 
               MongoClient dbInstance = new MongoConnector("mongodb://localhost:27017").getInstance(); 
               MongoCollection menu = dbInstance.getDatabase("restaurant").getCollection("menu"); 
      
    //  prepare document list 
               List<Document> foodList = new ArrayList<>(); 
               int counter = 1; 
               Random random = new Random(); 
               String namePrefix = "Item"; 
               while(counter < 6){ 
                   String itemName = namePrefix + String.valueOf((counter+1)); 
                   foodList.add(new Document("name",itemName).append("price",random.nextDouble() * 100)); 
                   ++counter; 
               } 
    //  insert many documents into the collection 
               menu.insertMany(foodList); 
           }catch(InstantiationException error){ 
               System.out.println(error.getMessage()); 
           } 
       } 
    }

    After the code is executed, we could get the following result from the shell:

    Using the Mongo Java Driver

    Read Documents:

    The simplest way to query data from mongo is to find everything in a collection. This is the default behaviour of the find method when no arguments are passed to it.

    import com.mongodb.client.MongoClient; 
    import com.mongodb.client.MongoCollection; 
    import com.mongodb.client.MongoCursor; 
    import org.bson.Document; 
      
    public class Main { 
       public static void main(String args[]){ 
           try{ 
               MongoClient dbInstance = new MongoConnector("mongodb://localhost:27017").getInstance(); 
               MongoCollection menu = dbInstance.getDatabase("restaurant").getCollection("menu"); 
               MongoCursor<Document> menuCursor = menu.find().iterator(); 
               try { 
                   while (menuCursor.hasNext()) { 
                       System.out.println(menuCursor.next().toJson()); 
                   } 
               }finally { 
                   menuCursor.close(); 
               } 
           }catch(InstantiationException error){ 
               System.out.println(error.getMessage()); 
           } 
       } 
    }

    There is a couple of important things to be noted here: First is that we use a cursor to retrieve data and the second is the `hasNext()` method on the cursor.

     
    Like with most other databases, in the interest of optimizing read performance, a cursor is used to retrieve data. The `find` method returns an Iterable, on which, when we call the `iterator` method we get a cursor.

     
    Calling the `next` method directly on the cursor will throw an exception if the collection is empty or when there’s no more data to retrieve. Hence we first check if data exists by using the `hasNext` method which returns a boolean based on the availability of data to retrieve.

     
    When we execute the above snippet of code, we would get the following result:

    Using the Mongo Java Driver

    Projecting the Result-Set:

    Those familiar with a SQL database would already know how the projections in the returned result-set of a query could be modified with the select statement. Similar projection of fields could be done in Mongo by using the `Projections` class.

    By default, as shown in the section above, all the fields are projected. Let’s modify and project only the `name` field:

    import com.mongodb.client.MongoClient; 
    import com.mongodb.client.MongoCollection; 
    import com.mongodb.client.MongoCursor; 
    import com.mongodb.client.model.Projections; 
    import org.bson.Document; 
    import org.bson.conversions.Bson; 
      
    public class Main { 
       public static void main(String args[]){ 
           try{ 
               MongoClient dbInstance = new MongoConnector("mongodb://localhost:27017").getInstance(); 
               MongoCollection menu = dbInstance.getDatabase("restaurant").getCollection("menu"); 
      
               Bson projectedFields = Projections.fields( 
                       Projections.include("name"), 
                       Projections.excludeId()); 
      
      
               MongoCursor<Document> menuCursor = menu.find().projection(projectedFields).iterator(); 
      
               try { 
                   while (menuCursor.hasNext()) { 
                       System.out.println(menuCursor.next().toJson()); 
                   } 
               }finally { 
                   menuCursor.close(); 
               } 
      
           }catch(InstantiationException error){ 
               System.out.println(error.getMessage()); 
           } 
       } 
    }

    When we execute the above code, only the name field from the documents in the collection will be projected the result-set of the query:

    Using the Mongo Java Driver

    Querying With Filters:

    Another most common use case in reading data from a database is applying some sort of filters to find the data that satisfies a certain condition or a set of conditions.
    We could do that using `Filters` in the Java Mongo Driver as follows:

    import com.mongodb.client.MongoClient; 
    import com.mongodb.client.MongoCollection; 
    import com.mongodb.client.MongoCursor; 
    import com.mongodb.client.model.Filters; 
    import com.mongodb.client.model.Projections; 
    import org.bson.Document; 
    import org.bson.conversions.Bson; 
      
    public class Main { 
       public static void main(String args[]){ 
           try{ 
               MongoClient dbInstance = new MongoConnector("mongodb://localhost:27017").getInstance(); 
               MongoCollection menu = dbInstance.getDatabase("restaurant").getCollection("menu"); 
      
               Bson projectedFields = Projections.fields(Projections.excludeId()); 
               Bson priceFilter = Filters.and(Filters.gt("price", 70), Filters.lt("price", 98)); 
      
               MongoCursor<Document> menuCursor = menu.find(priceFilter).projection(projectedFields).iterator(); 
      
               try { 
                   while (menuCursor.hasNext()) { 
                       System.out.println(menuCursor.next().toJson()); 
                   } 
               }finally { 
                   menuCursor.close(); 
               } 
      
           }catch(InstantiationException error){ 
               System.out.println(error.getMessage()); 
           } 
       } 
    }

    Now that we have placed a price filter to filter items that have a price greater than 70 and lesser than 98, our result-set will be as follows:

    Using the Mongo Java Driver

    Update Documents:

    To update a single document, we could use the `updateOne` method and update multiple documents the `updateMany` method. We can modify one or more fields in the documents through an update operation. 

    A code snippet for a single document update can be given as follows:

    import com.mongodb.client.MongoClient; 
    import com.mongodb.client.MongoCollection; 
    import com.mongodb.client.model.Filters; 
    import com.mongodb.client.model.Updates; 
    import com.mongodb.client.result.UpdateResult; 
    import org.bson.conversions.Bson; 
      
    public class Main { 
       public static void main(String args[]){ 
           try{ 
               MongoClient dbInstance = new MongoConnector("mongodb://localhost:27017").getInstance(); 
               MongoCollection menu = dbInstance.getDatabase("restaurant").getCollection("menu"); 
      
               Bson priceQuery = Filters.gt("price", 55); 
               Bson priceMutation = Updates.inc("price", -20); 
      
               UpdateResult resultSet =  menu.updateOne(priceQuery,priceMutation); 
      
               System.out.println("Number of Documents Filtered By the Query : " + resultSet.getMatchedCount()); 
               System.out.println("Number of Documents Modified By the Query : " + resultSet.getModifiedCount()); 
      
           }catch(InstantiationException error){ 
               System.out.println(error.getMessage()); 
           } 
       } 
    }

    The above code will find the first document that matches the query and will decrease the price by 20 in the found document.

    We can confirm that only a single document was affected by observing the output of the code:

    Using the Mongo Java Driver

    Let’s modify the above code to update multiple documents filtered with the same query:

    UpdateResult resultSet =  menu.updateMany(priceQuery,priceMutation);

    If we looked at the output, we can infer that multiple documents were actually modified:

    Using the Mongo Java Driver

    Delete Documents:

    Similar to other write operations, it is possible to delete one or many documents by using the appropriate methods exposed by the driver. Let’s look at a snippet to delete a single document from the collection:

    import com.mongodb.client.MongoClient; 
    import com.mongodb.client.MongoCollection; 
    import com.mongodb.client.model.Filters; 
    import com.mongodb.client.result.DeleteResult; 
    import org.bson.conversions.Bson; 
      
    public class Main { 
       public static void main(String args[]){ 
           try{ 
               MongoClient dbInstance = new MongoConnector("mongodb://localhost:27017").getInstance(); 
               MongoCollection menu = dbInstance.getDatabase("restaurant").getCollection("menu"); 
      
               System.out.println("Number of Documents In Collection Before Delete Operation: " + menu.countDocuments()); 
      
               Bson nameFilter = Filters.eq("name", "Item3"); 
      
               DeleteResult resultSet =  menu.deleteOne(nameFilter); 
      
               System.out.println("Number of Documents Deleted: " + resultSet.getDeletedCount()); 
               System.out.println("Number of Documents In Collection After Delete Operation: " + menu.countDocuments()); 
           }catch(InstantiationException error){ 
               System.out.println(error.getMessage()); 
           } 
       } 
    }

    The code will find a single document that has the value “Item3” for the field “name” and will delete it from the collection. We can verify this from the output logged in the console on executing the code:

    Using the Mongo Java Driver

    To delete many documents, let’s modify the filter query to match all documents that have a price greater than 70.  
    Our collection’s current state is as follows:

    [
      {
        _id: ObjectId("619767db0e4cbd63a03cd155"),
        name: 'Test Item 1',
        price: 80.5
      },
      {
        _id: ObjectId("61976d76077b0c0b360b744b"),
        name: 'Item2',
        price: 56.80710292448832
      },
      {
        _id: ObjectId("61976d76077b0c0b360b744d"),
        name: 'Item4',
        price: 73.7484483637489
      },
      {
        _id: ObjectId("61976d76077b0c0b360b744e"),
        name: 'Item5',
        price: 53.243517433833034
      },
      {
        _id: ObjectId("61976d76077b0c0b360b744f"),
        name: 'Item6',
        price: 73.84947772559507
      }
    ]

    So, with the discussed filter, we should be deleting 3 documents from the collection.

    Let’s do that with the following code:

    import com.mongodb.client.MongoClient;
    import com.mongodb.client.MongoCollection;
    import com.mongodb.client.model.Filters;
    import com.mongodb.client.result.DeleteResult;
    import org.bson.conversions.Bson;
     
    public class Main {
       public static void main(String args[]){
           try{
               MongoClient dbInstance = new MongoConnector("mongodb://localhost:27017").getInstance();
               MongoCollection menu = dbInstance.getDatabase("restaurant").getCollection("menu");
     
               System.out.println("Number of Documents In Collection Before Delete Operation: " + menu.countDocuments());
     
               Bson priceFilter = Filters.gt("price", 70);
     
               DeleteResult resultSet =  menu.deleteMany(priceFilter);
     
               System.out.println("Number of Documents Deleted: " + resultSet.getDeletedCount());
               System.out.println("Number of Documents In Collection After Delete Operation: " + menu.countDocuments());
           }catch(InstantiationException error){
               System.out.println(error.getMessage());
           }
       }
    }

    As expected, on execution, the above code deletes 3 documents and leaves us with 2 documents in the collection:

    Using the Mongo Java Driver

    Looking to land a job? Discover the best programming course to boost your career! Gain valuable skills and knowledge with our unique programming courses. Start your journey today!

    Using the Mongo Java Driver:

    We just saw how to use Java Driver for Mongo in our codebase and perform the fundamental operations of creating, reading, updating and deleting documents from a collection.

    Additionally, we also discussed how to programmatically create databases and collections using the APIs exposed by the driver.

    The Java driver for Mongo is feature-packed with advanced capabilities such as aggregation. If you are interested in furthering your depths about it, the official documentation might be a good starting point.

    Profile

    Parthipan Natkunam

    Author

    Parthipan is a full-stack capable, software engineer with 7 years of industry experience, specialized in front-end engineering. Certified "AWS Developer Associate", who has worked in industries such as Ed-tech, IoT and Cyber security with companies spanning across multiple countries with varied tech stacks. Language agnostic by practice but fluent in TypeScript and JavaScript. Loves open-source and enjoys creating quality software products from scratch.

    Share This Article
    Ready to Master the Skills that Drive Your Career?

    Avail your free 1:1 mentorship session.

    Select
    Your Message (Optional)

    Upcoming Web Development Batches & Dates

    NameDateFeeKnow more
    Course advisor icon
    Course Advisor
    Whatsapp/Chat icon