Skip to content

5. MongoDB and Java

Let's go to view hot to acces MongoDB from our Java programs. Firtsly, as we view in unit 2, we study how to acces directly and then with elements like ORM.

5.1. Drivers

As we already know, to connect from our applications to a database we need a controller or driver. MongoDB offers official drivers for a multitude of platforms, including C, C++, C#, NodeJS, Python, and of course, Java, among many others.

Focusing on Java, MongoDB offers us two drivers:

  • The Java driver for synchronous applications.
  • The Reactive Streams driver for processing asynchronous Streams.

Although currently there is a trend towards reactive programming, we are going to work with the Java synchronous driver to make it easier to understand and focus on the actual access to the data.

5.1.1. The Java driver

Using the MongoDB Driver for Java we can connect to both a local or remote database, as well as a MongoDB Atlas cluster. This driver (MongoDB Java Driver) can be found in the Maven repositories, and provides a large number of classes and interfaces to facilitate working with MongoDB from Java.

In a Gradle project we should use:

Bash
implementation group: 'org.mongodb', name: 'mongo-java-driver', version: '3.12.10'

whereas in a Maven project:

XML
1
2
3
4
5
<dependency>
    <groupId>org.mongodb</groupId>
    <artifactId>mongo-java-driver</artifactId>
    <version>3.12.10</version>
</dependency>

5.2. Connection to a database

To connect and communicate with a database we need a client. In the case of the Java driver for MongoDB, the client is implemented through the MongoClient class.

The MongoClient class represents a set of connections to a MongoDB server. These connections are thread-safe, that is, several threads of execution can safely access them.

The way to create MongoClient instances is through the MongoClients.create() method. Also, generally, we only need one instance of this class, even in multi-threaded applications. The MongoClients create method takes as an argument a Connection String, with the following simplified format (the clearer parameters are optional):

Bash
mongodb:// [user:password @] host[:port] /?options

So, a way to obtain, for example, a connection to the local server would be:

Java
String uri = "mongodb://localhost:27017";
MongoClient mongoClient = MongoClients.create(uri);

The MongoClient class, among others, supports the following methods:

  • getDatabase(String name) → Gets a reference to a database whose name is passed as an argument.
  • listDatabaseNames() Gets a list of Strings (MongoIterable interface) with the names of the server's databases.
  • close() Closes the connection to the server. It should always be done when it is no longer going to be used.

5.2.1. MongoDatabase

The getDatabase() method of the MongoClient class returns a reference to an object that implements the MongoDatabase interface, which represents a connection to a database. This interface defines the following methods:

  • getCollection(String name) → Gets a reference to the collection.
  • listCollectionNames() → Gets a list of Strings (MongoIterable interface) with the names of the collections in the database.
  • listCollections() → Gets a list of references (MongoCollection) to the collections in the database.
  • createCollection(String name) → Creates a new collection with the specified name in the database
  • drop() → Drops the database

Here you will find a sample of connection and list of database and collections of a given server:

Java
public MongoClient connectServer(){
  String uri = "mongodb://root:toor@localhost:27017";
  MongoClient mongoClient = MongoClients.create(uri);
  return mongoClient;
}

public void disConnect(MongoClient client){
  client.close();
}

public void getInfo(MongoClient client) {
  // get list of databases
  for (String dbname : client.listDatabaseNames()) {
      // Write its name
      System.out.println("Database: " + dbname);

      // Get a database reference
      MongoDatabase db = client.getDatabase(dbname);

      // Get database collections
      MongoIterable<String> colecciones = db.listCollectionNames();

      // show collections name
      for (String coleccion : colecciones) {
          System.out.println("\t\t > " + coleccion);
      }
  }
}

5.3. Queries

The getCollection() method of MongoDatabase() provides us with a Document collection (MongoCollection<Document>), on which we will be able to perform queries using the find() method. This method, which we already know from the MongoDB shell, will allow us to filter documents based on certain criteria.

These criteria are expressed as filters (query filters in the documentation), and can contain several query operators on some fields that will determine which documents in the collection are included as results.

The Filter class provides us with factory methods to perform these queries, similar to how we worked with the MongoDB shell. This class gives us:

  • Empty query, with Filters.empty().
  • Comparison operators: To perform queries based on values in the collection:
  • Filters.eq(key, value), Filters.gt(key, value), Filters.gte(key, value), Filters.lt(key, value) or Filters.lte(key, value).
  • Logical operators: To perform logical operations on the result of other queries: Filter.and(other_filters), Filter.or(other_folters), etc.
  • Array operators: They allow us to perform queries based on the value or number of elements of a vector: Filters.size(vector, size).
  • Other operators, such as Filter.exists() or Filter.regex(), to check for the existence of a key or perform a regular expression search.

In addition to filters, we will also be able to include aggregation operations, through the aggregate() method of a MongoCollection instance. You can check the documentation about aggregations in the MongoDB aggregation operations guide.

On the other hand, the MongoDB driver API also allows us to perform field projections using the Projections class, which offers the Projections.fields(), Projections.include() or Projections.excludeID() methods.

Sample of find films from a given year, only 10 resuts:

Java
public void getPelisAnyo(MongoClient client, int anyo) {

    // get collection from database
    MongoDatabase db=client.getDatabase("mflix");

    // get documents from that colection
    MongoCollection<Document> colPelis = db.getCollection("movies");

    // And now, we apply a filter and limit
    FindIterable<Document> docsPelis = colPelis
            .find(Filters.eq("year", anyo))
            .limit(10);

    // we show it
    for (Document doc : docsPelis) {
        System.out.println(doc.toString());
    }
}

Remember

Document class have several method to work like Json Documents in unit 1. We can get each field by given key, getting its value

Another sample with filters and projections:

Java
public void getPelisEntre(MongoClient client, int anyo1, int anyo2) {

    // check anyo values
    if (anyo1>anyo2){
        int tmp=anyo1;
        anyo1=anyo2;
        anyo2=tmp;
    }

    // get document collection
    MongoDatabase db=client.getDatabase("mflix");
    MongoCollection<Document> colPelis = db.getCollection("movies");

    // Creamos el filtro
    Bson filter=Filters.and(
        Filters.gte("year", anyo1),
        Filters.lte("year", anyo2)
    );

    // Create projecction
    Bson projection=Projections
            .fields(Projections.include("title", "year"),
                    Projections.excludeId());

    // Run the filters
    FindIterable<Document> DocsPelis = colPelis
            .find(filter)
            .projection(projection);

    // Show the films
    for (Document doc : DocsPelis) {
        System.out.println(doc.toString());
    }
}