Querying MongoDB Views in Java Spring Boot Applications

Learn how to query MongoDB views in a Java Spring Boot application using the MongoTemplate interface and the repository pattern.

In MongoDB, views act like a lens, allowing users to see data in structured ways without altering the original collections. They enhance data security by exposing only specific fields, streamlining complex queries into simpler forms, and maintaining consistent application logic. So it makes sense to leverage this MongoDB capability and integrate it into our Java projects using the Spring Data MongoDB library.

Before You Start

For the rest of this post, I will assume you understand how MongoDB views work. If you don't, you can check the following articles before reading this one: 

It is also important to know that I will use standard (in-memory) MongoDB views.

Creating the Initial Collections 

Let's go ahead and create two collections that will be the initial data sources for a MongoDB view:

  • An aircraft collection

  • A flights collection

Flights have a reference to an aircraft by using the aircraftId field.

// Create and populate aircraft collection
db.createCollection("aircraft");
db.aircraft.insertMany([
    { _id: 1, model: "Boeing 737-700", nbPassengers: 200, range: 5000, operator: "Austrian" },
    { _id: 2, model: "Airbus A321", nbPassengers: 220, range: 6800, operator: "Air France" },
    { _id: 3, model: "Embraer E175-E2", nbPassengers: 80, range: 3000, operator: "LOT" },
]);

// Create and populate flights (link via aircraftid)
db.createCollection("flights");
db.flights.insertMany([
    { from: "Vienna", to: "Amsterdam", aircraftId: 1 },
    { from: "Paris", to: "Lyon", aircraftId: 2 }
])

Creating a MongoDB $lookup View

With the collections in place, it's time to create a MongoDB view to merge flight information with aircraft information.

db.createView("detailedFlights", "flights", [
    {
        $lookup: {
            from: "aircraft", localField: "aircraftId", foreignField: "_id", as: "lookup"
        }
    },
    {
        $unwind: {
            path: "$lookup"
        }
    },
    {
        $project:{
            _id: 0,
            from: 1,
            to: 1,
            aircraft: "$lookup.model",
            operatedBy: "$lookup.operator"
        }
    }
])

This will create a new standard view that will perform an inner join between flights and aircraft by using the aircraftId field. The resulting view and its associated data will look like this:

+--------+-----------+----------------+------------+
|  from  |    to     |    aircraft    | operatedBy |
+--------+-----------+----------------+------------+
| Vienna | Amsterdam | Boeing 737-700 | Austrian   |
| paris  | Lyon      | Airbus A321    | Air France |
+--------+-----------+----------------+------------+

Set Up a Spring Boot Project 

It's time to see how we can query this view from a Java Spring Boot application. 

Add the Spring Boot Starter Data MongoDB Dependency

<!-- Maven -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-mongodb</artifactId>
    <version>3.1.2</version>
</dependency>
## Gradle
implementation 'org.springframework.boot:spring-boot-starter-data-mongodb:3.1.2'

Create a Class That Will Be Used To Access the detailedFlights View

import org.springframework.data.mongodb.core.mapping.Document;

/*
This document is linked to the "detailedFlights" view.
 */
@Document(collection = "detailedFlights")
public class DetailedFlight {
    public String to;
    public String from;
    public String aircraft;
    public String operatedBy;
}

Explanation:

The DetailedFlight class is defined. It's annotated with @Document(collection = "detailedFlights"), which specifies that instances of this class should be retrieved from the MongoDB view named "detailedFlights".

As you can see, mapping a Java class to a MongoDB view is the same as mapping it to a collection. We are using the same @Document annotation.

Querying the MongoDB view

Using MongoOperations or MongoTemplate

With the mapping in place, let's go ahead and write some queries. I'll start by using the MongoOperations interface. You will achieve the same results by using the concrete MongoTemplate class.

private final MongoOperations mongoOperations;

    public void run(String... args) throws Exception {
        // all flights
        var detailedFlights = this.mongoOperations.find(new Query(), DetailedFlight.class);

        // filter by property
        var flightFromParisQuery = Query.query(Criteria.where("from").is("Paris"));
        var flightFromParis = this.mongoOperations.find(flightFromParisQuery, DetailedFlight.class);

        // count
        var nbDetailedFlights = this.mongoOperations.count(new Query(), DetailedFlight.class);
}

Using the Repository pattern

We can achieve the same outcome with repositories. We'll start by creating a new repository interface named DetailedFlightRepository.

@Repository
public interface DetailedFlightRepository extends CrudRepository<DetailedFlight, String> {
    List<DetailedFlight> findByFromIs(String departureCity);
}

We can now go ahead and replace our initial queries with calls to the repository.

private final DetailedFlightRepository repository;

public void run(String... args) throws Exception {
    // all flights
    var detailedFlights = this.repository.findAll();

    // filter by property
    var flightFromParisQuery = this.repository.findByFromIs("Paris");

    // count
    var nbDetailedFlights = this.repository.count();
}

As you can observe, working with MongoDB views is no different than querying collections from a Spring application perspective. The main difference is that you can not modify views. So, any invocation that attempts to change/remove/create an element of the view will throw an exception.

Previous
Previous

Creating MongoDB Lookup Views Programmatically in Java Spring Applications

Next
Next

Creating Inner Join And Left Join Lookup Views in MongoDB: A Step-by-Step Guide