Explore Developer Center's New Chatbot! MongoDB AI Chatbot can be accessed at the top of your navigation to answer all your MongoDB questions.

MongoDB Developer
Java
plus
Sign in to follow topics
MongoDB Developer Centerchevron-right
Developer Topicschevron-right
Languageschevron-right
Javachevron-right

MongoDB Advanced Aggregations With Spring Boot and Amazon Corretto

Aasawari Sahasrabuddhe5 min read • Published Jun 26, 2024 • Updated Jun 26, 2024
SpringMongoDBAggregation FrameworkJava
FULL APPLICATION
Facebook Icontwitter iconlinkedin icon
Rate this tutorial
star-empty
star-empty
star-empty
star-empty
star-empty

Introduction

In this tutorial, we'll get into the understanding of aggregations and explore how to construct aggregation pipelines within your Spring Boot applications.
If you're new to Spring Boot, it's advisable to understand the fundamentals by acquainting yourself with the example template provided for performing Create, Read, Update, Delete (CRUD) operations with Spring Boot and MongoDB before delving into advanced aggregation concepts.
This tutorial serves as a complement to the example code template accessible in the GitHub repository. The code utilises sample data, which will be introduced later in the tutorial.
As indicated in the tutorial title, we'll compile the Java code using Amazon Corretto.
We recommend following the tutorial meticulously, progressing through each stage of the aggregation pipeline creation process.
Let's dive in!

Prerequisites

This tutorial follows a few specifications mentioned below. Before you start practicing it, please make sure you have all the necessary downloads and uploads in your environment.
  1. A free Atlas tier, also known as an M0 cluster.
  2. Sample Data loaded in the cluster.
  3. Spring Data Version 4.2.2.
  4. MongoDB version 6.0.3.
  5. MongoDB Java Driver version 4.11.1.
Let’s understand each of these in detail.

Understanding and installing Corretto

Corretto comes with the ability to be a no-cost, multiplatform, production-ready open JDK. It also provides the ability to work across multiple distributions of Linux, Windows, and macOS.
You can read more about Amazon Corretto in Introduction to Amazon Corretto: A No-Cost Distribution of OpenJDK.
We will begin the tutorial with the first step of installing the Amazon Corretto 21 JDK and setting up your IDE with the correct JDK.
Step 1: Install Amazon Corretto 21 from the official website based on the operating system specifications.
Step 2: If you are on macOS, you will need to set the JAVA_HOME variable with the path for the Corretto. To do this, go to the system terminal and set the variable JAVA_HOME as:
1export JAVA_HOME=/Library/Java/JavaVirtualMachines/amazon-corretto-21.jdk/Contents/Home
Once the variable is set, you should check if the installation is done correctly using:
1java --version
2openjdk 21.0.2 2024-01-16 LTS
3OpenJDK Runtime Environment Corretto-21.0.2.13.1 (build 21.0.2+13-LTS)
4OpenJDK 64-Bit Server VM Corretto-21.0.2.13.1 (build 21.0.2+13-LTS, mixed mode, sharing)
For any other operating system, you will need to follow the steps mentioned in the official documentation from Java on how to set or change the PATH system variable and check if the version has been set.
Once the JDK is installed on the system, you can set up your IDE of choice to use Amazon Corretto to compile the code.
At this point, you have all the necessary environment components ready to kickstart your application.

Creating the Spring Boot application

In this part of the tutorial, we're going to explore how to write aggregation queries for a Spring Boot application.
Aggregations in MongoDB are like super-powered tools for doing complex calculations on your data and getting meaningful results back. They work by applying different operations to your data and then giving you the results in a structured way.
But before we get into the details, let's first understand what an aggregation pipeline is and how it operates in MongoDB.
Think of an aggregation pipeline as a series of steps or stages that MongoDB follows to process your data. Each stage in the pipeline performs a specific task, like filtering or grouping your data in a certain way. And just like a real pipeline, data flows through each stage, with the output of one stage becoming the input for the next. This allows you to build up complex operations step by step to get the results you need.
By now, you should have the sample data loaded in your Atlas cluster. In this tutorial, we will be using the sample_supplies.sales collection for our aggregation queries.
The next step is cloning the repository from the link to test the aggregations. You can start by cloning the repository using the below command:
1git clone https://github.com/mongodb-developer/spring-boot-mongodb-aggregations.git
Once the above step is complete, upon forking and cloning the repository to your local environment, it's essential to update the connection string in the designated placeholder within the application.properties file. This modification enables seamless connectivity to your cluster during project execution.

README

After cloning the repository and changing the URI in the environment variables, you can try running the REST APIs in your Postman application.
All the extra information and commands you need to get this project going are in the README.md file which you can read on GitHub.

Writing aggregation queries in Spring

The Aggregation Framework support in Spring Data MongoDB is based on the following key abstractions:
  • Aggregation
  • AggregationDefinition
  • AggregationResults
The Aggregation Framework support in Spring Data MongoDB is based on the following key abstractions: Aggregation, AggregationDefinition, and AggregationResults.
While writing the aggregation queries, the first step is to generate the pipelines to perform the computations using the operations supported.
The documentation on spring.io explains each step clearly and gives simple examples to help you understand.
For the tutorial, we have the REST APIs defined in the SalesController.java class, and the methods have been mentioned in the SalesRepository.java class.
The first aggregation makes use of a simple $match operation to find all the documents where the storeLocation has been specified as the match value.
1db.sales.aggregate([{ $match: { "storeLocation": "London"}}])
And now when we convert the aggregation to the spring boot function, it would look like this:
1@Override
2public List<SalesDTO> matchOp(String matchValue) {
3MatchOperation matchStage = match(new Criteria("storeLocation").is(matchValue));
4Aggregation aggregation = newAggregation(matchStage);
5AggregationResults<SalesDTO> results = mongoTemplate.aggregate(aggregation, "sales", SalesDTO.class);
6return results.getMappedResults();
7}
In this Spring Boot method, we utilise the MatchOperation to filter documents based on the specified criteria, which in this case is the storeLocation matching the provided value. The aggregation is then executed using the mongoTemplate to aggregate data from the sales collection into SalesDTO objects, returning the mapped results.
The REST API can be tested using the curl command in the terminal which shows all documents where storeLocation is London.
The next aggregation pipeline that we have defined with the rest API is to group all documents according to storeLocation and then calculate the total sales and the average satisfaction based on the matchValue. This stage makes use of the GroupOperation to perform the evaluation.
1@Override
2public List<GroupDTO> groupOp(String matchValue) {
3MatchOperation matchStage = match(new Criteria("storeLocation").is(matchValue));
4GroupOperation groupStage = group("storeLocation").count()
5 .as("totalSales")
6 .avg("customer.satisfaction")
7 .as("averageSatisfaction");
8ProjectionOperation projectStage = project("storeLocation", "totalSales", "averageSatisfaction");
9Aggregation aggregation = newAggregation(matchStage, groupStage, projectStage);
10AggregationResults<GroupDTO> results = mongoTemplate.aggregate(aggregation, "sales", GroupDTO.class);
11return results.getMappedResults();
12}
The REST API call would look like below:
1curl http://localhost:8080/api/sales/aggregation/groupStage/Denver | jq
Total sales and the average satisfaction for storeLocation as "Denver"
The next REST API is an extension that will streamline the above aggregation. In this case, we will be calculating the total sales for each store location. Therefore, you do not need to specify the store location and directly get the value for all the locations.
1@Override
2public List<TotalSalesDTO> TotalSales() {
3GroupOperation groupStage = group("storeLocation").count().as("totalSales");
4SkipOperation skipStage = skip(0);
5LimitOperation limitStage = limit(10);
6Aggregation aggregation = newAggregation(groupStage, skipStage, limitStage);
7AggregationResults<TotalSalesDTO> results = mongoTemplate.aggregate(aggregation, "sales", TotalSalesDTO.class);
8return results.getMappedResults();
9}
And the REST API calls look like below:
1curl http://localhost:8080/api/sales/aggregation/TotalSales | jq
Total Sales for each store Location
The next API makes use of $sort and $limit operations to calculate the top 5 items sold in each category.
1@Override
2public List<PopularDTO> findPopularItems() {
3UnwindOperation unwindStage = unwind("items");
4GroupOperation groupStage = group("$items.name").sum("items.quantity").as("totalQuantity");
5SortOperation sortStage = sort(Sort.Direction.DESC, "totalQuantity");
6LimitOperation limitStage = limit(5);
7Aggregation aggregation = newAggregation(unwindStage,groupStage, sortStage, limitStage);
8return mongoTemplate.aggregate(aggregation, "sales", PopularDTO.class).getMappedResults();
9}
1curl http://localhost:8080/api/sales/aggregation/PopularItem | jq
top 5 items sold in each category
The last API mentioned makes use of the $bucket to create buckets and then calculates the count and total amount spent within each bucket.
1@Override
2public List<BucketsDTO> findTotalSpend(){
3ProjectionOperation projectStage = project()
4 .and(ArrayOperators.Size.lengthOfArray("items")).as("numItems")
5 .and(ArithmeticOperators.Multiply.valueOf("price")
6 .multiplyBy("quantity")).as("totalAmount");
7
8BucketOperation bucketStage = bucket("numItems")
9 .withBoundaries(0, 3, 6, 9)
10 .withDefaultBucket("Other")
11 .andOutputCount().as("count")
12 .andOutput("totalAmount").sum().as("totalAmount");
13
14Aggregation aggregation = newAggregation(projectStage, bucketStage);
15return mongoTemplate.aggregate(aggregation, "sales", BucketsDTO.class).getMappedResults();
16}
1curl http://localhost:8080/api/sales/aggregation/buckets | jq
calculates the count and total amount spent within each bucket

Conclusion

This tutorial provides a comprehensive overview of aggregations in MongoDB and how to implement them in a Spring Boot application. We have learned about the significance of aggregation queries for performing complex calculations on data sets, leveraging MongoDB's aggregation pipeline to streamline this process effectively.
As you continue to experiment and apply these concepts in your applications, feel free to reach out on our MongoDB community forums. Remember to explore further resources in the MongoDB Developer Center and documentation to deepen your understanding and refine your skills in working with MongoDB aggregations.
Top Comments in Forums
There are no comments on this article yet.
Start the Conversation

Facebook Icontwitter iconlinkedin icon
Rate this tutorial
star-empty
star-empty
star-empty
star-empty
star-empty
Related
Tutorial

Schema Performance Evaluation in MongoDB Using PerformanceBench


Apr 02, 2024 | 20 min read
Tutorial

Spring Data Unlocked: Getting Started With Java and MongoDB


Nov 11, 2024 | 5 min read
Quickstart

Building Quarkus Application with MongoDB and Panache


Dec 03, 2024 | 5 min read
Tutorial

Building a Semantic Search Service With Spring AI and MongoDB Atlas


Oct 24, 2024 | 9 min read
Table of Contents