ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 스키마의 유연성을 위한 mongo db 사용
    프로젝트/AutoMeet 2024. 4. 11. 13:10

    지금까지 프로젝트를 할 때에는 db로 RDBMS인 mysql을 사용했다. (추가로 redis로 jwt token 받는 정도??)

    그 이유는 가장 보편적이고 간편하며 널리 사용되기 때문이다.

     

    이번 프로젝트에서 회의를 진행하고 끝날 때 회의 데이터를 저장해야하는 요구사항이 생겼다. 제목, 회의 요약 내용 등을 비롯해서 데이터를 저장하는데 RDBMS에 저장하는 것보다 Nosql에 저장하는 게 좋을 것 같다는 생각이 들었지만, 확신은 없었다.

     

    하지만 ERD를 설계하던 도중, 회의 참여자 수가 고정되지 않는다는 문제점이 생겼다. 회의에 2명이 참가할수도, 4명이 참가할 수도 있는데 회의 table에 참여 인원을 고정시킨 member1 ~ member4 중에서 필요없는 컬럼을 null로 설정하는 것은 효율적이지 않다고 생각했다. List에 저장한다고 할 지라도 테이블끼리의 관계를 어떻게 맺어야 하는지에 대해 생각해보면 복잡한 과정이 필요하다.

     

    따라서 유연하게 데이터를 저장할 수 있는 mongo db를 사용하기로 했다.

     

     

     

    Meet collection

    @Document(collection = "meet")
    @Setter
    @Getter
    public class Meet {
    
        @Id
        private String id;
        private String title;
        private int content;
        private List<Long> userIds; // 참여한 user들을 리스트로 저장
    }

    mongo db의 컬렉션을 사용할 때에는 @Document 어노테이션을 사용한다. PK 값에는 @Id 어노테이션을 붙여주고, 참여자의 목록은 2명 이상일 것이므로 List로 선언해준다.

     

    List에는 2명, 4명이 들어와도 상관없이 컬렉션에 데이터를 저장할 수 있다.

     

     

     

    MeetRepository

    public interface MeetRepository extends MongoRepository<Meet, String> {
    
    }

    MongoRepository를 상속받아서 Spring data mongo db로 repository의 인터페이스를 선언한다. RDBMS와 비슷하게 기본적인 쿼리는 자동으로 제공하며, 더 필요한 쿼리들은 따로 선언해서 사용하면 된다.

     

     

    MeetService

    @Service
    @RequiredArgsConstructor
    public class MeetService {
    
        private final MeetRepository meetRepository;
    
        public Meet createMeet(Meet user) {
            return meetRepository.save(user);
        }
    
        public List<Meet> getAllMeets() {
            return meetRepository.findAll();
        }
    
        public Meet getMeetById(String id) {
            return meetRepository.findById(id).orElse(null);
        }
    
        public void deleteMeetById(String id) {
            meetRepository.deleteById(id);
        }
    }

    service 계층의 코드는 기존에 해왔던 것들과 크게 다를 것이 없기 때문에 생략한다.

     

     

    MeetController

    @RestController
    @RequiredArgsConstructor
    @RequestMapping("/meet")
    public class MeetController {
    
        private final MeetService meetService;
    
        @PostMapping
        public Meet createUser(@RequestBody Meet user) {
            return meetService.createMeet(user);
        }
    
        @GetMapping
        public List<Meet> getAllUsers() {
            return meetService.getAllMeets();
        }
    
        @GetMapping("/{id}")
        public Meet getUserById(@PathVariable String id) {
            return meetService.getMeetById(id);
        }
    
        @DeleteMapping("/{id}")
        public void deleteUserById(@PathVariable String id) {
            meetService.deleteMeetById(id);
        }
    }

    컨트롤러도 마찬가지이다.

     

     

    이제 postman으로 데이터를 넣어보자

    위의 사진은 참여자를 2명 넣었을 때와 4명 넣었을 때의 예이다.

    (물론 실제로는 수동으로 넣지 않고, 회의에 참여한 사용자들의 실제 id를 넣을 것이다.)

     

     

    조회를 해보면 잘 나오는 것을 확인할 수 있다.

     

    mysql로 테이블을 만들었다고 생각하면 user 테이블 간의 연관관계와 참여자의 인원에 따라서 유연하지 못할 수도 있었는데, mongo db는 유연한 설계가 가능했다.

     

     

    // repository
    public interface MeetRepository extends MongoRepository<Meet, String> {
        List<Meet> findByUserIdsContains(Long userId);
    }
    
    // service
    public List<Meet> findUserMeet(Long userId) {
        return meetRepository.findByUserIdsContains(userId);
    }
    
    // controller
    @GetMapping("/user/{userId}")
    public List<Meet> getUsersMeet(@PathVariable Long userId) {
        return meetService.findUserMeet(userId);
    }

    자신이 참여한 회의 목록을 보고싶을 때에도 위와 같이 조회하면 되기 때문에 RDBMS보다 유연하다는 Nosql의 장점을 이번 프로젝트에서 잘 살릴 수 있을 것이다.

     

     

     

     

    느낀점

    이전 프로젝트에서는 항상 mysql을 사용했었는데, 사실 db는 여러 db 중에서 요구사항에 맞는 db를 선택해서 사용해야 한다. Nosql은 RDBMS보다 유연하고 빠르기 때문에 mongo db와 redis와 같은 db가 많이 사용되며, mysql과 같은 RDBMS는 회원 정보 등 중요한 데이터들을 관리하는데 사용된다고 들었는데, 이번 기회에 여러 db를 학습해보면 좋겠다는 생각이 들었다.

     

    db는 프로젝트 전에 선택하는 것이 아니라 요구사항에 맞춰서 가장 적합한 db를 선택하는 것을 명심하고 가장 최선의 설계를 하는 백엔드 개발자가 되자!

Designed by Tistory.