Mis Documentos

Barra lateral de múltiples raíces

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

Descripción general

Un pequeño helper de consulta para desarrolladores de RDBMS que eran nuevos en MongoDB creció de acuerdo a las necesidades del proyecto real, explicando la historia y los criterios de diseño hasta convertirse en una capa de conveniencia de MongoDB basada en el controlador en 1.0.0.


Historia de origen

He estado desarrollando principalmente en RDBMS durante aproximadamente 4 años y estaba bastante familiarizado con AWS RDS en entornos de producción. Al comenzar un nuevo proyecto personal, elegí MongoDB por primera vez y, a medida que lo conocía, sentí que era una herramienta que podría cambiar significativamente mi productividad de desarrollo, más que simplemente ser una base de datos con un esquema flexible.

Particularmente, MongoDB Atlas se sentía como un nuevo mundo para mí. Podía usar búsqueda especializada y búsqueda vectorial en una sola plataforma de datos, que antes pensaba que requeriría sistemas separados, y las tareas operativas como copias de seguridad, monitoreo y escalado eran mucho más convenientes en comparación con mi experiencia previa solo con AWS RDS. Si se necesitaban escalas y funciones más especializadas, podría separar motores de búsqueda o bases de datos vectoriales como servicios separados, pero en la etapa de crear y operar un proyecto rápidamente, el alcance que podía resolver con solo Atlas era muy atractivo.

El problema era que escribir consultas dinámicas era muy lento para mí, que era nuevo en MongoDB. Al principio, la forma findBy... del repositorio era suficiente, pero a medida que las condiciones de búsqueda se volvían más complejas, tenía que ensamblar manualmente Query, Criteria y expresiones de operadores. En un estado no familiar, ensamblar condiciones repetitivas era propenso a errores tipográficos, y seguir escribiendo el mismo tipo de código ralentizaba mucho el desarrollo.

Comenzó con un DSL simple para consultas

Así que lo primero que creé fue una pequeña clase para hacer simplemente la R de CRUD. Este fue el punto de partida de lo que ahora se llama ReactiveMongoDsl. En ese momento, no había funciones como agregación, pipeline o lookup, y solo se trataba de ensamblar un poco más rápido Query, Criteria y paginación de ReactiveMongoTemplate. Pensé que el resto del trabajo podría hacerse usando el ReactiveMongoTemplate básico o el controlador de MongoDB directamente.

Sin embargo, un desarrollador con el que trabajaba pensaba de manera diferente. También era nuevo en MongoDB y cada vez que necesitaba operaciones como upsert o bulk, me preguntaba primero si la DSL que había creado tenía esa funcionalidad. Podría haberle dicho que usara la API básica directamente, pero pensé que él también experimentaría las mismas dificultades que yo había sentido al aprender MongoDB por primera vez. Así que comencé a agregar una función a la ReactiveMongoDsl cada vez que surgía una necesidad.

Al principio tenía alrededor de 600 líneas, y cuando llegó a 1,000 líneas, no pensé que fuera necesario dividirlo en varias clases. Cuando alcanzó alrededor de 2,000 líneas, dudé un poco, pero la estructura para la separación parecía hacer que el tamaño fuera aún mayor, y sobre todo, honestamente, me daba pereza hacer ese trabajo. Cuando superó las 5,000 líneas, no pude posponerlo más y moví algunas funciones que podían separarse, pero ya era una carga grande dividir el flujo central en partes más finas. La razón por la que la clase central es grande no es porque diseñé una enorme DSL desde el principio, sino porque se ha acumulado la historia de las funciones necesarias en un solo punto de entrada.

Así, después de agregar consultas, agregaciones, lookup, actualizaciones atómicas, bulk, historial, Atlas Search y Vector Search, en algún momento la mayoría de las funciones que necesitaba al usar MongoDB en un proyecto Java estaban incluidas. En lugar de mantenerlo como un helper interno de un solo proyecto, lo separé para que pudiera usarse de la misma manera en varios proyectos, y ese es el proceso de nacimiento de reactive-mongo-dsl.

De helper de Spring a biblioteca basada en el controlador.

El punto de partida era un helper para usar ReactiveMongoTemplate más cómodamente, pero a medida que las funciones crecieron y comencé a reutilizar en varios proyectos, decidí que no tenía sentido que el modelo de ejecución de un marco específico se convirtiera en el límite de la biblioteca. El núcleo de 1.0.0 utiliza MongoExecutionContext como contrato de ejecución y usa directamente el MongoDB Reactive Streams Driver.

Este cambio no es para excluir Spring Data MongoDB. En aplicaciones Spring, se pueden conectar el nombramiento de colecciones de ReactiveMongoTemplate, MongoConverter, conversiones personalizadas y auditoría reactiva a través del adaptador MongoExecutionContext. El núcleo se mantiene independiente del marco, y solo las aplicaciones necesarias continúan utilizando la configuración existente de Spring.

Al mismo tiempo, se ha vuelto más claro que no se implementarán nuevamente las funciones que ya ofrece bien el controlador dentro de la DSL. La agregación general puede recibir etapas de Bson tal cual, y para Search/Vector hay escapes como SearchOperator, VectorSearchQuery, driverOptions(...), stage(Bson). Esta es una elección para permitir el uso de nuevas funciones del controlador sin esperar la próxima distribución de la DSL.

Filosofía de desarrollo

No oculta MongoDB.

No quería crear un ORM que transformara las funciones de MongoDB en conceptos de otras bases de datos. Conecto las consultas, agregaciones, transacciones, Atlas Search y Vector Search de MongoDB en flujos más cortos y fáciles de descubrir.

Solo agrego las funciones que realmente se necesitaban.

No es una biblioteca que se implementó después de diseñar primero la lista de funciones. Se añadieron funciones de consulta porque eran necesarias en el proyecto operativo, se añadieron funciones de upsert y bulk porque eran necesarias, y se añadieron Atlas Search y Vector Search para la funcionalidad de búsqueda.

Prioriza la productividad sobre la perfección estructural.

No afirmamos que una clase central grande sea una estructura ideal. En el inicio, era más importante que el equipo pudiera manejar rápidamente las operaciones de MongoDB de la misma manera, y todavía priorizamos el flujo de uso real sobre la abstracción en sí.

No recreamos lo que el Driver ya hace.

Si el MongoDB Java Driver tiene un constructor tipado, utilizamos ese tipo tanto como sea posible. Las combinaciones repetitivas que el DSL puede reducir de manera valiosa se ofrecen como API de conveniencia, pero no duplicamos el API del Driver simplemente cambiando el nombre.

Debería ser posible descender a la API básica.

No creo que el DSL reemplace todas las situaciones. Se dejan salidas como Bson, filtros/ordenadores/opciones del Driver, y personalizadores de publicadores, y se puede usar directamente el Driver de MongoDB si es necesario.

Los cuatro flujos tratados en el documento actual.

Consulta Mongo general.

Este es el flujo en el que comenzó esta biblioteca. Se configura la condición y la ejecución en el orden execute* → fields(...) → end() → find/findAll/count/delete/exists/atomicUpdate.

Agregación nativa del Driver.

Para controlar directamente desde la primera etapa del pipeline o usar la nueva funcionalidad de agregación proporcionada por el Driver, se utiliza el flujo aggregation().stage(Bson). El DSL puede pasar etapas que el Driver ya proporciona, como $score y $scoreFusion, sin volver a implementarlas.

Búsqueda en Atlas

Este es un flujo añadido al aplicar Atlas Search al proyecto sin introducir primero un servicio de búsqueda separado. Se configuran text, compound, score, highlight y sequence token después de search(index).

Búsqueda Vectorial

Este es un flujo añadido para conectar la búsqueda de embedding dentro de MongoDB. Se configuran opciones de query vector o embedding automatizado, ANN/ENN, pre/post filter y opciones de embedding anidado/arreglo.

Modelo de ejecución de la versión 1.0.0.
text

Separar la consulta general y la búsqueda/vector es para no ocultar las restricciones reales del pipeline de MongoDB. $search y $vectorSearch tienen restricciones en la primera etapa, y las funciones que requieren que el llamador controle toda la primera etapa pueden descender a aggregation().

Alcance utilizado en proyectos reales

Se pasan pares sin condiciones como null para ensamblar condiciones de búsqueda dinámicas por pantalla.

Se separan data y totalCount con PageStream para mantener el flujo de procesamiento masivo en estado de publicador reactivo.

Se crean operaciones seguras contra ejecuciones duplicadas con atomicUpdate().upsertOne().document().setOnInsert(...).

Se almacenan datos recopilados y datos de integración externa mediante bulk upsert basado en ID o clave de trabajo.

Se devuelven los resultados de lookup y el conteo total en un solo pipeline con executeLookupAndCount.

Se utilizan el token de secuencia de Atlas Search y la consulta de embedding automatizado de Vector Search.

Las nuevas etapas de agregación proporcionadas por el Driver se conectan directamente a aggregation().stage(Bson) o a stage(Bson) de Search/Vector.

Si se necesita atomicidad entre operaciones del DSL, se especifica el alcance de la transacción ClientSession con getTxJob(...).

© 2026 Byeolnaerim. Todos los derechos reservados.IntroducciónPolítica de privacidad