Spring Data Reactive MongoDB — Aggregation Pipeline

Vinoth Selvaraj
3 min readOct 29, 2020

--

In this article, I would like to show you the Mongo aggregation pipeline using Spring Data Reactive MongoRepository and Reactive MongoTemplate.

Project Setup:

Lets first create a simple spring boot project with these dependencies.

Sample Application:

Let’s consider an application in which freelancers register themselves with their skill sets. The information is stored in the mongoDB as shown below.

{
"name": "sam",
"age": 40,
"skills": [ "js", "react", "python"]
}

{
"name": "jack",
"age": 38,
"skills": [ "js", "angular", "postgres"]
}

{
"name": "james",
"age": 30,
"skills": [ "java", "reactor", "mongo"]
}

{
"name": "smith",
"age": 32,
"skills": [ "qa", "selenium"]
}

Users of the application would like to see for each skill set/technology, all the available freelancers. So the UI expectation is more or less like this.

{
"js":[
"sam",
"jack"
],
"java":[
"james"
],
"selenium":[
"smith"
]
...
...
}

Let’s see how to achieve this using Spring Data.

MongoDB Setup:

I use docker-compose to set up mongodb and insert above documents.

version: "3"
services:
mongo:
image: mongo
ports:
- 27017:27017
environment:
MONGO_INITDB_ROOT_USERNAME: admin
MONGO_INITDB_ROOT_PASSWORD: password
mongo-express:
image: mongo-express
ports:
- 8081:8081
environment:
ME_CONFIG_MONGODB_ADMINUSERNAME: admin
ME_CONFIG_MONGODB_ADMINPASSWORD: password

Aggregation Pipeline:

To get the data in the format we want, we need to have following stages.

  • unwind: Each freelancer has an array of skill sets. It is stored in the skills field. This stage reconstructs the document in a way that a person with 3 skills would be presented as 3 persons with 1 skill each.
{ 
"$unwind" : {
"path" : "$skills"
}
}
  • group: Once you have unwinded (!), now we could group by skills field. For each skill, extract the names and push it to an array!
{
"$group":{
"_id":"$skills",
"names":{
"$push":"$name"
}
}
}
  • project: Once we have grouped the records, then we need to look for the specific fields we are interested in. I exclude the _id and retrieve as skill, then I also need the names field.
{
"$project":{
"_id":0,
"skill":"$_id",
"names":1
}
}

Now let’s get this implemented.

Entity Class:

Our entity class is represented as shown below.

@Data
@Document
@ToString
public class Freelancer {

@Id
private String id;
private String name;
private int age;
private List<String> skills;

}

Projection Class:

Since we would like to present the data differently, Lets create a model class for that.

@Data
@ToString
public class SkilledPeople {

private String skill;
private List<String> names;

}

Approach-1:

Mongo Reactive Repository:

Once we have our stages ready, we include them as an array of stages as value for the @Aggregation. Do note that it returns the instances of projection class we have defined above.

Application Properties:

spring.data.mongodb.database=admin
spring.data.mongodb.username=admin
spring.data.mongodb.password=password

Demo:

At this point, everything seems to be ready! We can run and verify.

Output:

We get the list of skills and corresponding freelancers who can be hired.

SkilledPeople(skill=js, names=[sam, jack])
SkilledPeople(skill=angular, names=[jack])
SkilledPeople(skill=postgres, names=[jack])
SkilledPeople(skill=selenium, names=[smith])
SkilledPeople(skill=java, names=[james])
SkilledPeople(skill=mongo, names=[james])
SkilledPeople(skill=react, names=[sam])
SkilledPeople(skill=python, names=[sam])
SkilledPeople(skill=reactor, names=[james])
SkilledPeople(skill=qa, names=[smith])

Approach-2:

Reactive Mongo Template + Aggregation Operation:

Spring Data provides the support for the Mongo aggregation framework. We can create all the stages as shown here and get it executed via Mongo template.

Demo:

We would get the same output, If we modify the runner as shown below.

Summary:

We were able to successfully demonstrate the mongo aggregation pipeline using both Spring Reactive Mongo Repository and Mongo Template.

The source code is available here.

Happy learning 🙂

--

--

Vinoth Selvaraj

Principal Software Engineer — passionate about software architectural design, microservices.