Spring Boot Query DSL Filters with MongoDB

1.Overview

Querydsl is a framework that helps to write type-safe SQL-like queries for any database. Pretty much like a proxy layer to the database layer.

2 Setup

Add dependency

<dependencies><dependency>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-apt</artifactId>
<version>${querydsl.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-jpa</artifactId>
<version>${querydsl.version}</version>
</dependency>
</dependencies>

To Generate Q-Classes

<plugins>    <plugin>
<groupId>com.mysema.maven</groupId>
<artifactId>apt-maven-plugin</artifactId>
<version>1.1.3</version>
<executions>
<execution>
<goals>
<goal>process</goal>
</goals>
<configuration>
<outputDirectory>target/generated-sources/java</outputDirectory>
<processor>
org.springframework.data.mongodb.repository.support.MongoAnnotationProcessor
</processor>
</configuration>
</execution>
</executions>
</plugin>
</plugins>

Run maven goal mvn clean install

Will generate new classes under target/generated-sources/java/{your package structure}

3. QueryDslPredicateExecutor & QuerydslBinderCustomizer

Enable Querydsl in our User repository using QueryDslPredicateExecutor

@Repository
public interface UserRepository extends BaseRepository<User>, QuerydslPredicateExecutor<User> {

}

Now to filter create a predicate under folder “repository → predicate → UserPredicate.java”

public class UserPredicate implements  QuerydslBinderCustomizer<QUser> {

@Override
public void customize(QuerydslBindings querydslBindings,
QUser qUser) {
// your queries will go here
}
}

4. Queries with DSL

Following imports can help to build the query

import com.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.core.types.dsl.EnumExpression;
import com.querydsl.core.types.dsl.StringExpression;

4.1 Eq operator

querydslBindings
.bind(qUser.active)
.as("active")
.first(BooleanExpression::eq);
// we are using boolean expression because `active` field type is boolean

4.2 String operator

querydslBindings.bind(qUser.fullName)
.as("name")
.first(StringExpression::eq);
// we are using boolean expression because `fullName` field type is string

4.3 Enum operator

querydslBindings.bind(qUser.type)
.as("type")
.first(EnumExpression::eq);
// we are using boolean expression because `type` field type is ENUM

4.4 In Array Operator (match-any)

querydslBindings.bind(qUser.cities)
.as("city-id")
.first((path, integers) -> path.any().in(integers));

4.5 Greater or Lesser operator

querydslBindings.bind(qUser.registerDate)
.as("register-date")
.first((path, value) -> path.goe(value));
or bindings.bind(qUser.registerDate)
.as("register-date")
.first((path, value) -> path.loe(value));

4.6 StartingWith and EndingWith

querydslBindings.bind(qUser.fullName)
.as("name")
.first((path, value) -> path.startsWith("Irfan"));

4.7 Between

querydslBindings.bind(qUser.createdAt)
.as("created-at")
.all((path, values) -> {
Iterator<? extends LocalDateTime> it = values.stream().sorted().iterator();
LocalDateTime from = it.next();
if (values.size() >= 2) {
LocalDateTime to = it.next();
return Optional.of(path.between(from, to));
} else {
return Optional.of(path.goe(from));
}
});

4.8 Transient Fields

This is used when you have a different type or format of the field than specified in the entity. For example if createAt is date-time field but you want to filter only by date without sending time in the query or in the URL. We can achieve this using the below method

Goto respective entity class in our case it is User

com/irfanbaigse/repository/entity/User.java and add folowing

// this fields will not be saved in db
@Transient

@Getter(value = AccessLevel.PRIVATE)
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
private LocalDate creationDateTo;
@Transient
@Getter(value = AccessLevel.PRIVATE)
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
private LocalDate creationDateFrom;

Then use it in predicate like this

// date fieldquerydslBindings.bind(qUser.creationDateFrom)
.as("created-from")
.first((path, value) -> qUser.createdAt.goe(value.atStartOfDay()));
querydslBindings.bind(qUser.creationDateTo)
.as("created-to")
.first((path, value) ->qUser.createdAt.loe(value.atTime(LocalTime.MAX)));
// end of the day

sample code can be found here on Github.

Reference

--

--

--

#java #nodejs #PHP #backend #developer #github #yii2 #symfony #laravel #aws #docker

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

How to send emails with just a few lines of code with Yagmail in Python

A new organization onboarding processes in a multi-hosts distributed HLF network

Why You Should Treat Your Main Branch as Production

Using form_tag and params to create a search or render a sorted view in Rails

I received Facebook T-shirt and became top 1000 contributor In Open Source Immersion 2020 ||

OpenCV Basic example

Structured Logging And Azure Log Analytics

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Irfan Baig

Irfan Baig

#java #nodejs #PHP #backend #developer #github #yii2 #symfony #laravel #aws #docker

More from Medium

Types of Update operations in MongoDB using Spring Boot

Spring boot with Mongo DB easy setup

Spring Cloud Gateway — Request filtering and redirection

Upload KMS key encrypted object from AWS S3 using AWS SDK 2.x for Java