Parses (a subset of) MongoDB expressions and convert them to Specifications to be used with Spring-Data-JPA 🎉.
spring-data-jpa-mongodb-expressions
allows you to use the MongoDB query syntax to query your relational database. This is specially useful to build dynamic search from the frontend app (a common case in business apps).
So, you can build the mongodb query-like json from the frontend app and pass it to the controller, and then optionally you enrich it with addtional conditions and pass it to the repository layer, in which the monogodb query will be translated automatically to JPA specification and executed.
This library provides an single interface ExpressionsRepository
to be extended by your application repositories:
public interface ExpressionsRepository<T, ID> extends JpaRepository<T, ID> {
List<T> findAll(Expressions expressions);
List<T> findAll(Expressions expressions, Sort sort);
Page<T> findAll(Expressions expressions, Pageable pageable);
}
See javadoc for more information.
- You need to customize the base repository to be the
ExpressionsRepositoryImpl
.
@Configuration
@EnableJpaRepositories(repositoryBaseClass = ExpressionsRepositoryImpl.class)
class ApplicationConfiguration { … }
- Change the parent repository of your JPA repositories:
@Repository
public interface EmployeeRepository extends ExpressionsRepository<Employee, Long> {
}
- Modify the search controller to accept
Expressions
in its parameter list:
@PostMapping("/search")
public ResponseEntity<Page<EmployeeDto>> search(@RequestBody Expressions expressions, Pageable pageable) {
// optional part
expressions.and(Expression.of("departementId", $eq, getCurrentUserDeptId()));
// add additional filters by ANDing or ORing more expression
return ok().body(
employeeRepository.findAll(expressions, pageable).map(employeeMapper::toDto)
);
}
And that's it, you can now send Mongodb-like json queries to the api.
The following is an example expressions that could be sent to the Controller Rest Apis, and will be deserialized into the Expressions
object.
1-
Expression:
{
"lastName": "ibrahim",
"$and": [
{
"birthDate": {"$gt": "1981-01-01"}
},
{
"birthDate": {"$lte": "1985-10-10"}
}
]
}
output:
... where last_name=? and birth_date>? and birth_date<=?
2-
Expression:
{
"$or": [
{"lastName": "ibrahim"},
{
"$and": [
{"firstName": "mostafa"},
{
"birthDate": {"$gt": "1990-01-01"}
}
]
}
]
}
output:
... where last_name = ? or first_name = ? and birth_date > ?
3-
Expression (joins):
{
"lastName": "ibrahim",
"department.name": {"$contains": "sw"}
}
output:
... from employee e inner join department d on e.department_id=d.id where e.last_name=? and d.name like ?
For a list of json queries see :
- the resources directory
- ExpressionsRepositoryImplTest.java
- Mongodb docs as a reference for the queries.
The following is a list of supported operators:
Operator | Description |
---|---|
$eq | col = val (if val is null then => col is null) |
$ne | col <> val (if val is null then => col is not null) |
$ieq | lower(col) = lower(val) |
$gt | col > val |
$gte | col >= val |
$lt | col < val |
$lte | col <= val |
$start | col like 'val%' |
$end | col like '%val' |
$contains | col like '%val%' |
$istart | lower(col) like 'lower(val)%' |
$iend | lower(col) like '%lower(val)' |
$icontains | lower(col) like '%lower(val)%' |
$in | col in (val1, val2, ...) |
$nin | col not in (val1, val2, ...) |
$or | expr1 or expr2 |
$and | expr1 and expr2 |
<dependency>
<groupId>com.github.mhewedy</groupId>
<artifactId>spring-data-jpa-mongodb-expressions</artifactId>
<version>0.0.2</version>
</dependency>
spring-data-jpa-mongodb-expressions
depends mostly on public APIs from JPA
and Spring-data-jpa
projects, such as javax.persistence.criteria.Predicate
, org.springframework.data.domain.Pageable
and org.springframework.data.jpa.domain.Specification
.
So unless the public APIs for JPA
and Spring-data-jpa
don't change, it is safe to use spring-data-jpa-mongodb-expressions
.
Also spring-data-jpa-mongodb-expressions
declares spring-boot-starter-data-jpa
as an optional dependency, which means it isn't a transitive dependency and no dependencies will be transferred to your project (from spring or what so ever) as a result of using spring-data-jpa-mongodb-expressions
.
See this snippet to see how to build the query from js.
Special thanks to Rashad Saif and Hamada Elnoby for helping in the design, inspring with ideas, and for doing the review for the code.