How to build custom queries with Spring Data Reactive MongoDB
Tags: java, tutorial, database, mongodb
Published: 2020-05-17 12:31:30

---
title: How to build custom queries with Spring Data Reactive MongoDB
published: true
description: 
cover_image: https://images.pexels.com/photos/3912948/pexels-photo-3912948.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260
tags: java, tutorial, database, mongodb
---
This post guides readers to implementation of update methods with Reactive MongoDB for Spring Data. It focuses on core principles of extending _ReactiveMongoRepository_ with custom functionality and gives four concrete examples.

## Getting started with ReactiveMongo for Spring Data

Out of the box, [Spring](https://www.mednikov.tech/error-handling-webflux/) supplies us with repositories, that offer basic CRUD functionality, e.g. insertion, deletion, update and retrieving data. In case of reactive MongoDB access, we talk about _ReactiveMongoRepository_ interface, which captures the domain type to manage as well as the domain type's id type. There are two ways to extend it functionality:

* Use _derived query methods_, which are generated from custom method signatures, you declare in the interface - like _findByFirstName_ - this is out of the scope of this post.
* Create a custom implementation and combine it with _ReactiveMongoRepository_ - this is what we will do in this article.

To start, you need to have a __reactive MongoDB__ starter defined with your dependencies management tool. If you use Maven, add following dependency in your _pom._:

```xml
<dependencies>
	<!-- Your app dependencies -->
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-data-mongodb-reactive</artifactId>
	</dependency>
</dependencies>
```

Let create a custom entity to use in our example. Let do a traditional example - [user management](https://www.mednikov.tech/two-factor-authentication-for-spring-webflux-apis/). This code declares a _User_ object that we will use in this post:

```java
@Value @AllArgsConstructor
@Document(collection = "users")
public class User {

    @NonFinal @Id String userId;
    String email;
    String password;
    List<Role> roles;
}
```

Next step is to declare a repository which extends _ReactiveMongoRepository_ For the purpose of tutorial, let create an ordinary user repository:

```java
@Repository
public interface UserRepository extends ReactiveMongoRepository<User, String> {}
```

This interface will provide us with basic CRUD functionality for _User_ entities, including:

* Save
* Retrieve by id
* Update
* Retrieve all
* Remove

This, however does not include custom features we may need to do with _User_ objects. For instance, we may need to update not a full record record, but only specific fields, like [password](https://www.mednikov.tech/two-factor-authentication-for-spring-webflux-apis/). Same way, we may need to handle changes for nested objects/arrays of the entity. To do this, we can't use derived query methods, but we have to declare a custom repository. Let see how to do this.

## How to extend ReactiveMongoRepository

The process to extend Spring's reactive Mongo repository with custom functionality takes 3 steps:

1. Create an interface that defines custom data management methods, like _CustomUserRepository_
2. Provide an implementation using _ReactiveMongoTemplate_ to access data source. The name of the implementation interface, should have _Impl_ postfix, like _CustomUsersRepositoryImpl_
3. Extend the core repository with custom repository interface. For example, _UserRepository extends ReactiveMongoRepository<User, String>, CustomUserRepository_

Let have a practical example. We already mentioned _UsersRepository_ as an entry point for data access operations. We will use this repository __in services__ to handle data source access. However, Spring will create only implementations for CRUD operations, and for custom method updates we will need to provide own implementations. But this is not a rocket science with Spring. 

The first thing is to create a custom interface to declare our own update methods. Let call it _CustomUserRepository_:

```java
public interface CustomUserRepository {

    Mono<User> changePassword (String userId, String newPassword);

    Mono<User> addNewRole (String userId, Role role);

    Mono<User> removeRole (String userId, String permission);

    Mono<Boolean> hasPermission (String userId, String permission);
}
```

Then, in the step 2, we need to provide a _custom implementation_. This is the step, where we will need to do most work. We will look on each method separately later, but for now we will provide an essential configuration. What do we need to do:

* Provide a dependency of type _ReactiveMongoTemplate_. We will use it to access an underlaying data source.
* Add a constructor, where Spring will inject the required bean. Also, annotate the constructor using _@Autowired_

Take a look on the code snippet below:

```java
public class CustomUserRepositoryImpl implements CustomUserRepository {

    private final ReactiveMongoTemplate mongoTemplate;

    @Autowired
    public CustomUserRepositoryImpl(ReactiveMongoTemplate mongoTemplate) {
        this.mongoTemplate = mongoTemplate;
    }

    @Override
    public Mono<User> changePassword(String userId, String newPassword) {
        return null;
    }

    @Override
    public Mono<User> addNewRole(String userId, Role role) {
        return null;
    }

    @Override
    public Mono<User> removeRole(String userId, String permission) {
        return null;
    }

    @Override
    public Mono<Boolean> hasPermission(String userId, String permission) {
        return null;
    }

}
```

Finally, we need to make Spring to know, that we want to use this repository alongside with the built-in one. For this, extend the _UserRepository_ with the _CustomUserRepository_ interface, like this:

```java
public interface UserRepository extends ReactiveMongoRepository<User, String>, CustomUserRepository {
	//...
}
```

So, now we are ready to do implementations of custom update methods.

## Implement custom update functionality

In this section we will look how to implement custom updates methods with Reactive MongoDB in Spring. Each method is described separately.

### Update an entity's field

The one of the most common requirements is to change a value of an entity's field. In our example we use _confirmed_ field to store if the user confirmed her/his account or not. Of course, in our example we concentrate only on database logic, and will not handle a confirmation workflow, so please assume that our _UserService_ did everything correctly and now uses a repository to update user's status. 

Take a look on the code snippet below:

```java
@Override
public Mono<User> changePassword(String userId, String newPassword) {
	// step 1
    Query query = new Query(Criteria.where("userId").is(userId)); 

    // step 2
    Update update = new Update().set("password", newPassword);

    // step 3
    return mongoTemplate.findAndModify(query, update, User.class);
}
```

Let examine what we do here:

1. Create a _query_ object that finds the concrete user with specific _userId_
2. Create an _update_ object to change the _confirmed_ field's value to _true_. For this, use _set()_ method that accepts as a first argument field's name (key) and as a second one new value
3. Finally execute an update using _mongoTemplate_ object. The method _findAndModify_ is used  to apply provided update on documents that match defined criteria.

Note, that basically, the flow is same if we use "traditional" synchronous Spring MongoDB. The only difference is the return type - instead of plain _User_ object, reacitve repository returns a _Mono_.

### Add to a nested array

An another widespread operation you may need to handle in your applications is to add a new entity in a nested array. Let say, that we want to add a new role for the specific user. In our example we store permssions in the nested list _roles_. 

Again, we don't focus on how actually permission management is done, and assume that _UserService_ does everything as needed. Here is an implementation:

```java
@Override
public Mono<User> addNewRole(String userId, Role role) {
	// step 1
	Query query = new Query(Criteria.where("userId").is(userId));

	// step 2
	Update update = new Update().addToSet("roles", role);

	// step 3
	return mongoTemplate.findAndModify(query, update, User.class);
}
```

Basically, steps are same. The only change is an _Update_ object. We use here _addToSet_ method which accepts a name of a nested array - _roles_ and an object to insert in it.

There is an another approach to add an object to a nested collection - _push_:

```java
// ..
Update updateWithPush = new Update().push("roles", role);
```

The difference between these two methods is following:

* _addToSet_ method does not allow duplicates and inserts an object __only__ if collection does not contain it already.
* _push_ method allows duplicates and can insert the same entity several times

### Remove from a nested array

Like we add something inside a nested collection, we may need to remove it. As we do in our examples role management, we may want to revoke given access rights from the user. To do this we actually need to remove an item from a nested collection. Take a look on the code snippet below:

```java
@Override
public Mono<User> removeRole(String userId, String permission) {
	// step 1
    Query query = new Query(Criteria.where("userId").is(userId));

    // step 2
    Update update = new Update().pull("roles",
         new BasicDBObject("permission", permission));

    // step 3
    return mongoTemplate.findAndModify(query, update, User.class);
}
```

The update object uses _pull_ method to remove a _role_ with a given _permission_ value. We assume that permissions are unique, but in a real life it is better to use some internal unique IDs for the nested object management. We can divide this step into two parts:

1. _pull_ operator accepts as a first argument a name of a nested collection
2. Second argument is a _BasicDBObject_ which specifies a criteria of which role we want to delete. In our case we use _permission_ field to specify it 

### Query by a nested object's field

We already mentioned, that Spring helps us to do querying with derived query methods, like _findByName_. Although, this will work with object's fields, but what if we want to query by a nested object? 

For the illustration we declared a method _hasPermission_ which returns a boolean value that indicates if a user has a specific access right, or in terms of our example - does a nested list _roles_ contains an entity with a specific _permission_ value.

Let see how we can solve this task:

```java
@Override
// 1
public Mono<Boolean> hasPermission(String userId, String permission) {

	// 2
	Query query = new Query(Criteria.where("userId").is(userId))
			.addCriteria(Criteria.where("roles.permission").is(permission)); //3

	// 4
	return mongoTemplate.exists(query, User.class);
}
```

Let go step by step:

1. Unlike previous methods, this method returns _Mono<Boolean>_ result, which wraps a boolean value that indicates a presence/absense of the desired permission. 
2. We need to combine two criterias, because we are looking for the specific user with specific permssion. _Query_ object offers fluent interface and we can chain criterias with _addCriteria_ method.
3. We build a query object which looks for a _role_ entity inside _roles_ array with the needed _permission_ value.
4. Finally, we call _exists_ method, which accepts a query and checks for an existance of the queried data

## Source code

That is how you can create custom update queries using Reactive MongoDB with [Spring](https://www.mednikov.tech/tag/spring-webflux/). You can find a complete source code in [this Github repository](https://github.com/mednikoviurii/spring-reactive-examples).