Is there something like JPA Specifications for Spring Data MongoDB Repositories?
If not, how can I make dynamic queries with repositories?
A classic scenario could be a search form with optional fields that the user will fill.
I found myself a way.
The trick can be done using QueryDSL, in the following way:
First, add the QueryDSL dependencies:
<dependency>
<groupId>com.mysema.querydsl</groupId>
<artifactId>querydsl-mongodb</artifactId>
<version>${querydsl-mongo.version}</version>
</dependency>
<dependency>
<groupId>com.mysema.querydsl</groupId>
<artifactId>querydsl-apt</artifactId>
<version>${querydsl-mongo.version}</version>
</dependency>
Then, configure the plugin in order to create Metamodels classes (their names will be the same of the documents with the letter Q as prefix: eg. QUser
):
<build>
<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>
</build>
Note the processor class: it's not the QueryDSL default one com.mysema.query.apt.morphia.MorphiaAnnotationProcessor, but the Spring Data MongoDB one org.springframework.data.mongodb.repository.support.MongoAnnotationProcessor
:
Spring Data Mongo provides a custom APT processor to generate the Metamodels instead of the one provided in QueryDSL, it will scan the Spring specific @Document instead of the Morphia specific annotations.
Now we can make our repository interface extending QueryDslPredicateExecutor<T>
:
public interface UserRepository extends MongoRepository<User, String>, QueryDslPredicateExecutor<User>,
QuerydslBinderCustomizer<QUser> {
}
We can now define Predicates when querying the repository:
QUser user = QUser.user;
BooleanExpression predicate = user.name.containsIgnoreCase("John");
userRepository.findAll(predicate);
QuerydslBinderCustomizer
helps you to define the binding of the Document's properties (see Spring documentation for further help).