본문 바로가기

Backend/Spring

Spring Boot Reactive Mongo Data QueryDSL

Spring Data MongoDB에서도 QueryDSL을 사용할 수 있어요.

build.gradle에 아래 설정만 잘 추가해주시면 됩니다.

예제에서는 Reactive Mongodb를 사용하고 있습니다.

build.gradle

plugins {
    id 'com.ewerk.gradle.plugins.querydsl' version '1.0.10'
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-data-mongodb-reactive'
    implementation 'com.querydsl:querydsl-mongodb'
    implementation 'com.querydsl:querydsl-apt'
}

def querydslGeneratedDir = "$buildDir/generated/querydsl" as Object

querydsl {
    library = "com.querydsl:querydsl-apt"
    springDataMongo = true
    querydslSourcesDir = querydslGeneratedDir
}

sourceSets {
    main.java.srcDir querydslGeneratedDir
}

configurations {
    querydsl.extendsFrom compileClasspath
}

compileQuerydsl {
    options.annotationProcessorPath = configurations.querydsl
}

BookRepository

public interface BookRepository extends ReactiveMongoRepository<Book, String>,
    ReactiveQuerydslPredicateExecutor<Book> {

}

Book

@Document(collection = "Book")
@Getter
@Setter
@Builder
public class Book {

  @Id
  private final String id;

  @CreatedDate
  private final LocalDateTime createdAt;

  @LastModifiedDate
  private final LocalDateTime updatedAt;

  private Set<Category> categories;

  private String title;

  private String introduction;

  private Set<String> authors;

  private LocalDate publishedDate;

  private Aggregation aggregation;
}

 

ReactiveQuerydslPredicateExecutor 만 추가해주면 됩니다.

그리고 gradle에서 compileQuerydsl 실행하면 build/generated 폴더 밑에 Q-Class가 생깁니다.

 

 

요런식으로 Q-Class 객체를 사용해서 조건문을 만들어주면 됩니다.

필드마다 다양한 조건이 있으니 코드 자동완성으로 잘 활용해보세요.

위의 방법으론 조회 쿼리만 만들 수 있습니다.

저는 개인적으로 딱 이 정도까지만 사용해서요.

다른 설정 방법과 기능이 더 있는지는 딥하게 찾아보지는 않았어요.

 

import static com.example.demo.domain.book.document.QBook.book;

public class BookService {

  public Mono<BookResponse> getBook(String bookId) {
    return bookRepository.findOne(book.id.eq(bookId))
        .switchIfEmpty(Mono.error(new ServiceException(ServiceMessage.NOT_FOUND_BOOK)))
        .map(BookResponse::of);
  }
  
  public Flux<BookResponse> getBooks(String keyword) {
    return bookRepository.findAll(book.title.contains(keyword), new OrderSpecifier<>(Order.ASC, book.createdAt))
        .switchIfEmpty(Flux.empty())
        .map(BookResponse::of);
  }
}

 

type-safe하게 긴 조건의 쿼리를 만들 수 있다는 장점이 있습니다.

  • MongoRepository에서 method명과 parameter명으로 쿼리를 만들면 한 줄로 매우 길어집니다.
  • MongoTemplate에서 Criteria으로 조건 쿼리를 만들면 type-safe하지 않은 단점이 있습니다.