My Library Docs

Multi-root Sidebar

flex-layout

  • Getting Started

  • Guides

  • Reference

typed-rx-http

  • Getting Started

  • Guides

  • Reference

global-rx-state

  • Getting Started

  • Guides

  • Reference

webflux-fe-dev-assistant

reactive-mongo-dsl


v0.0.11Drag to reorder

Overview

MongoDB가 처음이었던 RDBMS 개발자가 반복되는 쿼리 작성의 어려움을 줄이기 위해 만든 작은 조회 helper가, 실제 프로젝트의 요구를 따라 Java용 MongoDB 작업 DSL로 성장한 과정과 설계 기준을 설명합니다.


Origin story

저는 약 4년 동안 RDBMS를 중심으로 개발했고, 운영 환경도 대부분 AWS RDS에 익숙했습니다. 새로운 개인 프로젝트를 시작하면서 처음 MongoDB를 선택했는데, 알아갈수록 단순히 스키마가 유연한 데이터베이스라기보다 제 개발 생산성을 크게 바꿀 수 있는 도구라고 느꼈습니다.

특히 MongoDB Atlas는 제게 신세계에 가까웠습니다. 기존에는 별도 시스템을 붙여야 한다고 생각했던 전문 검색과 벡터 검색을 하나의 데이터 플랫폼 안에서 사용할 수 있었고, 백업·모니터링·확장 같은 운영 작업도 AWS RDS만 사용해 왔던 제 기준에서는 훨씬 편리했습니다. 더 전문적인 규모와 기능이 필요하다면 검색 엔진이나 벡터 데이터베이스를 별도 서비스로 분리할 수 있겠지만, 한 프로젝트를 빠르게 만들고 운영하는 단계에서는 Atlas 하나로 해결할 수 있는 범위가 매우 매력적이었습니다.

문제는 MongoDB가 처음인 제게 동적 쿼리를 작성하는 일이 너무 느렸다는 점이었습니다. 처음에는 repository의 findBy... 형태만으로도 충분했지만, 검색 조건이 복잡해지자 Query, Criteria와 연산자 문자열을 직접 조립해야 했습니다. 특히 "$eq" 같은 문자열 기반 표현을 반복해서 다루는 방식은 익숙하지 않은 상태에서 오타도 나기 쉽고, 코드를 작성하는 속도도 많이 떨어뜨렸습니다.

조회용 간이 DSL에서 시작했습니다

그래서 처음 만든 것은 CRUD 중 R만 간단하게 만들기 위한 작은 클래스였습니다. 현재 ReactiveMongoDsl이라는 이름으로 남아 있는 클래스의 시작점입니다. 당시에는 aggregation, pipeline, lookup 같은 기능이 전혀 없었고, ReactiveMongoTemplateQuery, Criteria, paging을 조금 더 빠르게 조립하는 정도였습니다. 나머지 작업은 기본 ReactiveMongoTemplate이나 MongoDB driver를 직접 사용해도 충분하다고 생각했습니다.

하지만 같이 일하던 개발자의 생각은 달랐습니다. 그 또한 MongoDB가 처음이었고, upsert나 bulk 같은 작업이 필요할 때마다 제가 만든 DSL에 해당 기능이 있는지 먼저 물어봤습니다. 기본 API를 직접 사용하라고 말할 수도 있었지만, 제가 처음 MongoDB를 배울 때 느꼈던 어려움을 그 역시 똑같이 겪을 것이라고 생각했습니다. 그래서 필요한 기능이 생길 때마다 ReactiveMongoDsl에 하나씩 추가하기 시작했습니다.

처음에는 약 600줄이었고, 1,000줄이 되었을 때도 굳이 여러 클래스로 나눌 필요는 없다고 생각했습니다. 2,000줄쯤 되었을 때는 조금 고민했지만, 분리를 위한 구조가 오히려 더 커지는 느낌도 있었고 무엇보다 솔직히 그 작업이 귀찮았습니다. 5,000줄을 넘겼을 때는 더 이상 미룰 수 없어 분리 가능한 기능 일부를 밖으로 옮겼지만, 이미 핵심 흐름을 세밀하게 다시 나누기에는 부담이 큰 상태였습니다. 현재 핵심 클래스가 약 8,000줄에 이르는 이유는 처음부터 거대한 DSL을 설계했기 때문이 아니라, 실제 프로젝트에서 필요했던 기능을 같은 진입점에 계속 쌓아 온 역사에 가깝습니다.

그렇게 조회, 집계, lookup, 원자 업데이트, bulk, history, Atlas Search와 Vector Search까지 추가하고 나니 어느 순간 Java 프로젝트에서 MongoDB를 사용할 때 제가 자주 필요로 하는 기능 대부분이 들어가 있었습니다. 한 프로젝트 안의 내부 helper로만 두기보다 여러 프로젝트에서 같은 방식으로 사용할 수 있도록 분리했고, 그것이 reactive-mongo-dsl의 탄생 과정입니다.

개발 철학

MongoDB를 감추지 않습니다

MongoDB의 기능을 다른 개념으로 바꾸는 ORM을 만들고 싶었던 것이 아닙니다. Query, Criteria, aggregation과 Atlas 기능을 더 짧고 발견하기 쉬운 흐름으로 연결합니다.

실제로 필요했던 기능만 추가합니다

기능 목록을 먼저 설계한 뒤 구현한 라이브러리가 아닙니다. 운영 프로젝트에서 조회가 필요해서 조회를, 동료가 upsert를 필요로 해서 upsert를, 검색 기능을 사용하게 되어 Atlas Search를 추가했습니다.

구조적 완벽함보다 생산성을 우선합니다

핵심 클래스가 큰 것은 이상적인 구조라고 주장하기 위해서가 아닙니다. 익숙하지 않은 MongoDB 작업을 팀이 같은 방식으로 빠르게 처리하는 것이 당시에는 더 중요한 문제였습니다.

기본 API로 내려갈 수 있어야 합니다

DSL이 모든 상황을 대신한다고 생각하지 않습니다. 더 특수한 기능이나 세밀한 제어가 필요하면 기존 ReactiveMongoTemplate과 MongoDB driver를 함께 사용할 수 있습니다.

현재 문서에서 다루는 세 가지 흐름

일반 Mongo Query

처음 이 라이브러리가 시작된 흐름입니다. execute* → fields(...) → end() → find/findAll/count/delete/exists/atomicUpdate 순서로 조건과 실행을 구성합니다.

Atlas Search

별도 검색 서비스 없이 Atlas Search를 프로젝트에 적용하면서 추가한 흐름입니다. search(index) 뒤에 text, compound, score와 sequence token을 구성합니다.

Vector Search

MongoDB 안에서 embedding 검색까지 연결하기 위해 추가한 흐름입니다. query vector 또는 text embedding, ANN/ENN와 filter를 명시적으로 구성합니다.

실제 프로젝트에서 사용하는 범위

조건이 없는 pair를 null로 넘겨 화면별 동적 검색 조건을 조립합니다.

PageStream으로 data와 totalCount를 분리해 대량 처리 흐름을 유지합니다.

atomicUpdate().upsertOne().document().setOnInsert(...)로 중복 실행에 안전한 작업을 만듭니다.

ID 또는 업무 키 기준 bulk upsert로 수집 데이터와 외부 연동 데이터를 저장합니다.

executeLookupAndCount로 lookup 결과와 전체 건수를 한 pipeline에서 반환합니다.

Atlas Search의 sequence token과 Vector Search의 automated embedding query를 사용합니다.

© 2026 Byeolnaerim. All rights reserved.소개개인정보처리방침