지금까지 몽고디비를 이용해 데이터를 조회하고 저장했는데, 큰 이점을 확인하지는 못했다.
실제 이커머스에는 데이터베이스에서 id로 조회하는 기능만 있는 것이 아니라 전체 상품을 보여주고 고객에게 상품을 고르게 하는 것이 더 일반적이다.
또한 고객에게 검색어를 입력하게 하고 그에 맞는 상품 목록을 보여주는 기능도 필요하다.
지금부터 검색 기능을 만들어보도록 하겠다.
검색어로 상품 목록을 조회하는 리포지토리 코드이다.
package com.greglturnquist.hackingspringboot.reactive.item;
import org.springframework.data.repository.reactive.ReactiveCrudRepository;
import reactor.core.publisher.Flux;
public interface ItemRepository extends ReactiveCrudRepository<Item, String> {
Flux<Item> findByNameContaining(String partialName);
}
이 리포지토리는 고객이 입력한 검색어가 이름에 포함된 상품을 반환하는 메소드를 가지고 있다.
메소드 이름에 포함된 containing이라는 일종의 키워드가 그 기능을 담당하며 개발자가 관련 구현 코드를 직접 구현할 필요는 없다.
스프링 데이터에서 정한 메소드 이름 규칙을 사용해서 리포지토리 메소드를 정의하면 일반적으로 필요한 쿼리문의 80% 정도를 직접 코드나 SQL 문을 작성하지 않고 자동으로 만들어낼 수 있다.
Item 객체에 description 등 몇 가지 필드가 더 있다고 가정하고 스프링 데이터의 메소드 이름 규칙을 알아보자.
package com.greglturnquist.hackingspringboot.reactive.item;
import org.springframework.data.annotation.Id;
import java.awt.*;
import java.util.Date;
public class Item {
private @Id String id;
private String name;
private String description;
private double price;
private String distributionRegion;
private Date releaseDate;
private int availableUnits;
private Point location;
private boolean active;
private Item() {}
}
상품의 여러 속성을 기준으로 쿼리문을 자동으로 만들어주는 메소드 이름 규칙은 다음과 같다.
| 쿼리 메소드 | 설명 |
|---|---|
| findByDescription(…) | description 값이 일치하는 데이터 질의 |
| findByNameAndDescription(…) | name값과 description 값이 모두 일치하는 데이터 질의 |
| findByNameAndDistributorRegion(…) | name값과 distributorRegion 값이 모두 일치하는 데이터 질의 |
| findTop10ByName(…) 또는 | |
| findFirst10ByName(…) | name 값이 일치하는 첫 10개의 데이터 질의 |
| findByNameIgnoreCase(…) | name 값이 대소문자 구분 없이 일치하는 데이터 질의 |
| findByNameAndDescriptionAllIgnoreCase(…) | name값과 description 값 모두 대소문자 구분 없이 일치하는 데이터 질의 |
| findByNameOrderByDescriptionAsc(…) | name 값이 일치하는 데이터를 description 값 기준 오름차순으로 정렬한 데이터 질의 |
| findByReleaseDateBefore(Date date) | releaseDate 값이 date보다 이전인 데이터 질의 |
| findByReleaseDateAfter(Date date) | releaseDate 값이 date 이후인 데이터 질의 |
| findByAvailableUnitsGreaterThan(int units) | availableUnits 값이 units보다 큰 데이터 질의 |
| findByAvailableUnitsGreaterThanEqual(int units) | availableUnits 값이 units보다 크거나 같은 데이터 질의 |
| findByAvailableUnitsLessThan(int units) | availableUnits 값이 units보다 작은 데이터 질의 |
| findByAvailableUnitsLessThanEqual(int units) | availableUnits 값이 units보다 작거나 같은 데이터 질의 |
| findByAvailableUnitsBetween(int from, int to) | availableUnits 값이 from과 to 사이에 있는 데이터 질의 |
| findByAvailableUnitsIn(Collection unitss) | availableUnits 값이 unitss 컬렉션에 포함돼 있는 데이터 질의 |
| findByAvailableUnitsNotIn(Collection unitss) | availableUnits 값이 unitss 컬렉션에 포함돼 있지 않은 데이터 질의 |
| findByNameNotNull() 또는 | |
| findByNameIsNotNull() | name 값이 null 이 아닌 데이터 질의 |
| findByNameNull() 또는 | |
| findByNameIsNull() | name 값이 null인 데이터 질의 |
| findByNameLike(String f) | name 값이 문자열 f를 포함하는 데이터 질의 |
| findByNameNotLike(String f) 또는 | |
| findByNameIsNotLike(String f) | name 값이 문자열 f를 포함하지 않는 데이터 질의 |
| findByNameStartingWith(String f) | name 값이 문자열 f로 시작하는 데이터 질의 |
| findByNameEndingWith(String f) | name 값이 문자열 f로 끝나는 데이터 질의 |
| findByNameNotContaining(String f) | name 값이 문자열 f를 포함하지 않는 데이터 질의 |
| findByNameRegex(String patter) | name 값이 pattern으로 표현되는 정규 표현식에 해당하는 데이터 질의 |
| findByLocationNear(Point p, Distance max) | location 값이 p 지점 기준 max 이내에서 가장 가까운 순서로 정렬된 데이터 질의 |
| findByLocationNear(Point p, Distance min, Distance max) | location 값이 p 지점 기준 거리 min 이상 max 이내에서 가장 가까운 순서로 정렬된 데이터 질의 |
| findByLocationWithin(Circle c) | location 값이 원 영역 c 안에 포함돼 있는 데이터 질의 |
| findByLocationWithin(Box b) | location 값이 직사각형 영역 b 안에 포함돼 있는 데이터 질의 |
| findByActiveIsTrue() | active 값이 true인 데이터 질의 |
| findByActiveIsFalse() | active 값이 false 인 데이터 질의 |
| findByLocationExists(boolean e) | location 속성의 존재 여부 기준으로 데이터 질의 |
여기에 굵은 글씨로 표시한 키워드는 deleteBy 메소드에서도 동일하게 사용할 수 있다.
<aside> 💡 표의 키워드는 몽고디비 기준이다. 대부분 다른 데이터 스토어에서도 사용할 수 있고, 데이터 스토어별 메소드 키워드는 해당 데이터 스토어용 스프링 데이터 레퍼런스 문서를 참고하면 된다.
</aside>