Mongo Repository & Mongo Template

Caesars·2024년 7월 14일
0

MongoDB

목록 보기
2/2

Mongo Repository를 써보고 후기를 정리합니다. 오랬동안 Mongo Template 만을 써와서 쓸 필요를 느끼지 못했습니다. 하지만 팀 내에서 MongoDB에 대해 잘 모르는 사람도 사용할 필요가 생겼기에 쉽게 사용할 수 있도록 하기 위해 기능의 일정 부분을 Repository로 전환했습니다.


MongoTemplate vs MongoRepository

  • MongoTemplate: MongoDB의 고급 기능을 사용할 때 유용합니다. 커스텀 쿼리, 복잡한 업데이트 작업, 그리고 MongoDB 집계 파이프라인을 쉽게 구현할 수 있습니다.
  • MongoRepository: Spring Data MongoDB에서 제공하는 리포지토리 추상화를 사용하여 기본적인 CRUD 작업을 쉽게 수행할 수 있습니다. 쿼리 메서드와 자동 생성되는 쿼리를 통해 생산성을 높일 수 있습니다.

코드

구성

Template
└── Service // service db를 사용하는 MongoTemplate
└── Api // api db를 사용하는 MongoTemplate
repository
└── ServiceRepository // service db와 연결해야하는 repo
└── UserRepository // service db와 연결해야하는 repo
└── ApiRepository // api db와 연결해야하는 repo

MongoConfig 설정

@Configuration
@EnableMongoAuditing
public class MongoConfig{

	// MongoProperties 에 설정한 주소로 접속
	@Bean
    public MongoClient mongoClient(MongoProperties mongoProperties){
    	MongoCredential credential = MongoCredential.createCredential(mongoProperties.getUsername(),
				mongoProperties.getAuthDatabase(), mongoProperties.getPassword().toCharArray());
		MongoClientSettings settings = MongoClientSettings.builder().credential(credential)
				.applyToClusterSettings(builder -> builder
						.hosts(Arrays.asList(new ServerAddress(mongoProperties.getHost(), mongoProperties.getPort()))))
				.build();

		return MongoClients.create(settings);
    }
    
    @Bean
	public MongoTemplate serviceTemplate(MongoClient mongoClientService) {
    	// service DB 사용
		MongoTemplate mongoTemplate = new MongoTemplate(mongoClientService, "service");
		((MappingMongoConverter) mongoTemplate.getConverter()).setTypeMapper(new DefaultMongoTypeMapper(null));
		return mongoTemplate;
	}
    
    @Bean
	public MongoTemplate apiTemplate(MongoClient mongoClientService) {
       	// api DB 사용
		MongoTemplate mongoTemplate = new MongoTemplate(mongoClientService, "api");
		((MappingMongoConverter) mongoTemplate.getConverter()).setTypeMapper(new DefaultMongoTypeMapper(null));
		return mongoTemplate;
	}
    
    //service.repository 패키지에 있는 repository는 serviceTemplate을 쓰도록 설정
	@EnableMongoRepositories(basePackages = "com.test.mongodb.service.repository", mongoTemplateRef = "serviceTemplate")
    public static class ServiceMongoConfig {}

	//api.repository 패키지에 있는 repository는 apiTemplate을 쓰도록 설정
    @EnableMongoRepositories(basePackages = "com.test.mongodb.api.repository", mongoTemplateRef = "apiTemplate")
    public static class ApiMongoConfig {}
}

(설정 부분에서 시간이 꽤 걸렸습니다)

위 코드에서는 하나의 MongoClient 인스턴스만 있지만, 여러대의 서버로 연결이 필요하다면 그만큼의 MongoClient 인스턴스가 필요합니다.

처음에는 여러개의 configuration 클래스를 만들고 @Configuration 어노테이션을 붙여 각각의 DB로 연결했었습니다. 추후 하나의 MongoConfig 안에 서브 클래스로 DB를 연결하는 방식이 더 깔끔해 보여 수정했습니다.

MongoTemplate 등록

@Bean
public MongoTemplate serviceTemplate(MongoClient mongoClientService) {
   	// service DB 사용
	MongoTemplate mongoTemplate = new MongoTemplate(mongoClientService, "service");
	((MappingMongoConverter) mongoTemplate.getConverter()).setTypeMapper(new DefaultMongoTypeMapper(null));
	return mongoTemplate;
}

MongoTemplate는 초기화 시점에 mongoClinet 인스턴스를 받습니다. 생성된 MongoTemplate은 바로 사용 가능합니다.

repository에 mongoTemplateRef 지정

Spring data는 @Repository 어노테이션이 붙은 인터페이스를 기준으로 자동 생성된 CRUD 기능을 제공한다.

여러 DB를 하는데 Repostiory들이 각자 사용할 mongoTemplate 인스턴스를 알려주기위해 mongoTemplateRef를 통해 bean의 이름을 지정하면 됩니다.

만약 MongoTemplate을 따로 지정해주지 않았다면 기본 템플릿(MongoTemplate) bean을 찾게 되는데 없다면 에러가 나게 됩니다.

@EnableMongoRepositories(basePackageClasses = com.test.mongodb.service.MyMongo.class, 
mongoTemplateRef = "serviceTemplate")

라고 class로 설정도 가능합니다. 하지만 class 자체와 연결되는 것이 아니라, 해당 class가 속한 패키지 내의 리포지토리들이MongoTemplate과 연결됩니다.

Repository 등록

package com.test.mongodb.service.repository;

public interface ServiceRepository extends JpaRepository<Data, Long>{
	
    List<Data> findAllBy();
    Optional<Data> findByRequestId(Long id);
    ....
}

..............................

package com.test.mongodb.api.repository;
public interface ApiRepository extends JpaRepository<ApiEntity, Long>{
	
    Optional<ApiEntity> findByApiId(Long id);
    ....
}

Service

@Service
public class ApiService {

    @Autowired
    private ApiRepository apiRepository;
    
    @Autowired
    private MongoTemplate apiTemplate;

	public Optional<ApiEntity> findById(Long id) {
    	/* apiTemplate.findOne(Query.query(Criteria.where("id")
        .is(id)), ApiEntity.class);
        */
        return apiRepository.findById(id);
    }

    public void deleteById(Long id) {
        apiRepository.deleteById(id);
    }

    
    ...
    
}

후기

간단한 CRUD 기능은 repository로 변환했습니다. 팀원이 mongo를 다루는데 거부감을 줄일것이라 생각합니다. 다만 복잡한 쿼리는 repository로 변환할 수가 없었기에 그대로 뒀습니다.

요약

MongoTemplate은 복잡한 쿼리가 필요한 경우에 사용합니다.
MongoRepository는 기본적인 CRUD 작업과 간단한 쿼리에 유용합니다.
두 가지를 상황에 따라 유연하게 사용하면 편합니다. 끝


참고

https://velog.io/@ur2e/Spring-Data-MongoDB-Multiple-database-config-0hco07aw
https://velog.io/@hanblueblue/MongoDB-MongoTemplate-vs.-MongoRepository

profile
잊기전에 저장

0개의 댓글