MongoDB 연습하기

bw1611·2023년 8월 17일
0

SpringBoot

목록 보기
6/6

MongoDB에 대해서 알기전에 Nosql이 뭔지 알고 넘어가도록 하자!

NoSql이란?


  • 비관계형 데이터베이스 유형을 가리키며 이 데이터베이스는 관게형 테이블과는 다른 형식으로 데이터를 저장합니다. NoSql 데이터베이스는 데이터 모델에 따라 유형이 다양하며 주요 유형으로는 문서, 키, 값, 그래프 등이 있습니다. 유연한 스키마를 제공하며 대량의 데이터와 높은 사용자 부하에도 손쉽게 확장이 가능하다는 장점이 있습니다.

📁MongoDB란?


  • MongoDB의 핵심이자, 기본 단위는 document이며, 이는 관계형 데이터베이스의 행과 유사합니다.
  • document는 정렬된 키와 값의 집합으로 이뤄져있습니다.
  • MongoDB는 데이터형과 대소문자를 구별하고, 키 값은 중복이 될 수 없습니다.

Local환경에서 mongoDB를 실행하기 위해서는 설치를 받아야 합니다.

📟작은 프로젝트에 MongoDB적용하기


implementation 'org.springframework.boot:spring-boot-starter-data-mongodb-reactive'
implementation 'org.springframework.boot:spring-boot-starter-webflux'
  • gradle에 MongoDB 의존성을 추가한다.
@Data
@Document(collection = "chat")
public class Chat {
    @Id
    private String id;
    private String msg;
    private String sender; // 보내는 사람
    private String receiver; // 받는 사람 (귓속말)
    private Integer roomNum; // 방 번호

    private LocalDateTime createdAt;
}
  • 우선 MongoDB는 @Entity를 사용하는 것 대신 @Document 어노테이션을 사용한다.
    "Collection" 몽고DB Document의 그룹이며 RDBMS의 Table과 개념이 유사합니다.
    컬렉션은 단일 데이터브에스에 존재하며 스키마를 강요하지 않습니다.
    ( 원래 collation으로 되어있었으나 목적에 맞는 collection으로 수정하였습니다. )
@RequiredArgsConstructor
@RestController
public class ChatController {

    private final ChatRepository chatRepository;
    
    @CrossOrigin
    @GetMapping(value = "/sender/{sender}/receiver/{receiver}", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<Chat> getMsg(@PathVariable String sender, @PathVariable String receiver) {
        return chatRepository.mFindBySender(sender, receiver)
                .subscribeOn(Schedulers.boundedElastic());
    }

    @CrossOrigin
    @GetMapping(value = "/chat/roomNum/{roomNum}", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<Chat> findByRoomNum(@PathVariable Integer roomNum) {
        return chatRepository.mFindByRoomNum(roomNum)
                .subscribeOn(Schedulers.boundedElastic());
    }

    @CrossOrigin
    @PostMapping("/chat")
    public Mono<Chat> setMsg(@RequestBody Chat chat){
        chat.setCreatedAt(LocalDateTime.now());
        return chatRepository.save(chat); // Object를 리턴하면 자동으로 JSON 변환 (MessageConverter)
    }
}
  • produces를 통해 텍스트 이벤트 스트림 미디어 타입을 지정합니다. HTTP 연결을 통해 지속적인 데이터 스트림을 전송하는 데 사용되는 형식입니다.
  • "subscribeOn" Flux의 구독이 시작되는 스레드를 설정합니다.
public interface ChatRepository extends ReactiveMongoRepository<Chat, String> {
    @Tailable
    @Query("{ sender : ?0, receiver : ?1}")
    Flux<Chat> mFindBySender(String sender, String receiver); // Flux (흐름) response를 유지하면서 데이터를 계속 흘려보내기

    @Tailable
    @Query("{ 'roomNum': ?0 }")
    Flux<Chat> mFindByRoomNum(Integer roomNum);
}
  • 커서를 닫지 않고 계속 유지하고 최신 DB 내용을 변환하게 되는 @Tailable 어노테이션을 추가하면 Flux를 통해서 데이터가 게속 흘러들어오게 되므로 새로 추가된 데이터를 변환합니다.

  • postMan을 이용하여 통신

  • mongoDB에 잘 저장되는 것을 확인할 수 있습니다.

🔨 진행하면서 나왔던 오류


2023-08-16T16:33:25.545+09:00 ERROR 10340 --- [ntLoopGroup-3-3] a.w.r.e.AbstractErrorWebExceptionHandler : [2cad4529-1]  500 Server Error for HTTP GET "/chat/roomNum/1"

org.springframework.data.mongodb.UncategorizedMongoDbException: Command failed with error 2 (BadValue): 'error processing query: ns=chatdb.chat batchSize=2Tree: roomNum $eq 1
Sort: {}
Proj: {}
 tailable cursor requested on non capped collection' on server localhost:27017. The full response is {"ok": 0.0, "errmsg": "error processing query: ns=chatdb.chat batchSize=2Tree: roomNum $eq 1\nSort: {}\nProj: {}\n tailable cursor requested on non capped collection", "code": 2, "codeName": "BadValue"}
	at org.springframework.data.mongodb.core.MongoExceptionTranslator.translateExceptionIfPossible(MongoExceptionTranslator.java:140) ~[spring-data-mongodb-4.1.2.jar:4.1.2]
	Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException: 
Error has been observed at the following site(s):
	*__checkpoint ⇢ Handler com.ll.mongoChat.ChatController#findByRoomNum(Integer) [DispatcherHandler]
	*__checkpoint ⇢ HTTP GET "/chat/roomNum/1" [ExceptionHandlingWebHandler]
  • tailable cursor가 capped collection이 아닌 컬렉션에서 요청되었음을 의미
    -> Tailable cursor는 capped collection에서만 사용할 수 있음
    -> Capped collection은 MongoDB에서 고정된 크기를 갖는 특수한 타입의 컬렉션

  • 해결방법
    1, mongoDB Shell 다운로드 (https://www.mongodb.com/try/download/shell)
    2, 받은 폴더 -> bin -> monosh.exe 실행
    3, 현재 설정한 DB 포트로 접속

    4, 해당 데이터베이스로 이동

    5, convertToCapped 명령어 입력
    -> db.runCommand( { convertToCapped: 'chat', size: 8192 } )
    6, 적용 여부 확인 ( capped: true로 되어있으면 성공 )

profile
Java BackEnd Developer

0개의 댓글