Meus Documentos

Barra Lateral Multi-raiz

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

Visão geral

Um pequeno helper de consulta para desenvolvedores de RDBMS que eram novos no MongoDB cresceu de acordo com as necessidades de projetos reais, explicando a história e os critérios de design até se tornar uma camada de conveniência MongoDB driver-first na versão 1.0.0.


História de origem

Desenvolvi principalmente em RDBMS por cerca de 4 anos e estava acostumado com ambientes operacionais, principalmente AWS RDS. Ao iniciar um novo projeto pessoal, escolhi o MongoDB pela primeira vez e, à medida que fui aprendendo, percebi que era uma ferramenta que poderia mudar significativamente minha produtividade de desenvolvimento, não apenas um banco de dados com esquema flexível.

Particularmente, o MongoDB Atlas parecia um novo mundo para mim. Eu poderia usar busca especializada e busca vetorial em uma única plataforma de dados, que antes achava que precisava de sistemas separados, e operações de manutenção como backup, monitoramento e escalabilidade eram muito mais convenientes do que eu estava acostumado com o AWS RDS. Se precisasse de uma escala e funcionalidades mais especializadas, poderia separar motores de busca ou bancos de dados vetoriais como serviços distintos, mas na fase de criar e operar rapidamente um projeto, a abrangência que o Atlas poderia resolver era muito atraente.

O problema era que, como era novo no MongoDB, escrever consultas dinâmicas era muito lento. No início, a forma findBy... do repositório era suficiente, mas à medida que as condições de busca se tornavam mais complexas, eu precisava montar manualmente Query, Criteria e expressões de operadores. A montagem repetitiva de condições em um estado não familiar era propensa a erros de digitação, e continuar escrevendo o mesmo tipo de código diminuía muito a velocidade de desenvolvimento.

Começou com um DSL simples para consulta

Portanto, o primeiro que criei foi uma pequena classe para simplificar a criação do R no CRUD. Este é o ponto de partida da classe que atualmente se chama ReactiveMongoDsl. Na época, não havia recursos como agregação, pipeline ou lookup, e era apenas uma forma de montar Query, Criteria e paginação um pouco mais rapidamente do que o ReactiveMongoTemplate do Spring Data. Eu achava que o restante poderia ser feito usando o ReactiveMongoTemplate básico ou o MongoDB Driver diretamente.

No entanto, a opinião do desenvolvedor com quem trabalhava era diferente. Ele também era novo no MongoDB e sempre perguntava se a DSL que eu criei tinha a funcionalidade necessária, como upsert ou bulk, sempre que precisava. Eu poderia ter dito para usar a API básica diretamente, mas pensei que ele também enfrentaria as mesmas dificuldades que eu tive ao aprender MongoDB pela primeira vez. Então, comecei a adicionar uma funcionalidade de cada vez à ReactiveMongoDsl sempre que surgia uma necessidade.

No início, tinha cerca de 600 linhas, e quando chegou a 1.000 linhas, ainda achava que não havia necessidade de dividir em várias classes. Quando chegou a cerca de 2.000 linhas, pensei um pouco, mas a estrutura para separação parecia estar crescendo ainda mais, e, acima de tudo, honestamente, era um trabalho chato. Quando ultrapassou 5.000 linhas, não pude mais adiar e movi algumas funcionalidades que poderiam ser separadas para fora, mas já estava em um estado em que era difícil dividir o fluxo central em partes menores. A razão pela qual a classe central é grande não é porque eu projetei uma DSL gigantesca desde o início, mas sim pela história de acumular continuamente funcionalidades necessárias em um único ponto de entrada em projetos reais.

Assim, após adicionar consulta, agregação, lookup, atualizações atômicas, bulk, histórico, Atlas Search e Vector Search, em algum momento, a maioria das funcionalidades que eu frequentemente precisava ao usar MongoDB em projetos Java já estava incluída. Em vez de mantê-las como helpers internos de um único projeto, separei-as para que pudessem ser usadas da mesma forma em vários projetos, e esse é o processo de nascimento do reactive-mongo-dsl.

De helper do Spring para biblioteca driver-first

O ponto de partida era um helper para usar ReactiveMongoTemplate de forma mais conveniente, mas à medida que as funcionalidades aumentaram e começaram a ser reutilizadas em vários projetos, percebi que o modelo de execução de um framework específico não deveria ser o limite da biblioteca. O núcleo da versão 1.0.0 usa MongoExecutionContext como contrato de execução e utiliza diretamente o MongoDB Reactive Streams Driver.

Essa mudança não é para excluir o Spring Data MongoDB. Em aplicações Spring, é possível conectar a nomeação de coleções do ReactiveMongoTemplate, MongoConverter, conversão personalizada e auditoria reativa ao adaptador MongoExecutionContext. O núcleo é mantido independente do framework, e apenas as aplicações necessárias continuam a usar as configurações existentes do Spring.

Ao mesmo tempo, a direção de não reimplementar funcionalidades que o MongoDB Driver já fornece dentro da DSL também se tornou mais clara. A agregação comum pode receber o estágio Bson diretamente, e para Search/Vector, há escape hatches como SearchOperator, VectorSearchQuery, driverOptions(...), stage(Bson). Essa é uma escolha para permitir que os usuários utilizem novas funcionalidades do Driver sem esperar pela próxima distribuição da DSL.

Filosofia de desenvolvimento

Não escondemos o MongoDB

Não era meu objetivo criar um ORM que transformasse as funcionalidades do MongoDB em conceitos de outros bancos de dados. Conectamos as consultas, agregações, transações, Atlas Search e Vector Search do MongoDB em fluxos mais curtos e fáceis de descobrir.

Adicionamos apenas as funcionalidades que realmente eram necessárias.

Não é uma biblioteca que foi implementada após o design da lista de funcionalidades. Foi necessário implementar a consulta em um projeto em operação, adicionar a funcionalidade de upsert e bulk, e incluir a pesquisa com Atlas Search e Vector Search.

Prioriza a produtividade em vez da perfeição estrutural.

Não afirma que uma classe central grande é a estrutura ideal. No início, era mais importante que a equipe lidasse rapidamente com operações do MongoDB de forma consistente, e ainda priorizamos o fluxo de uso real em vez da abstração em si.

Não recriamos o que o Driver já faz.

Se o MongoDB Java Driver tiver um builder tipado, usamos esse tipo sempre que possível. As combinações repetitivas que o DSL pode reduzir de forma valiosa são oferecidas como API de conveniência, mas não duplicamos a API do Driver apenas mudando o nome.

Deve ser possível descer para a API básica.

Não acreditamos que o DSL substitua todas as situações. Mantemos escape hatches como Bson, filtros/sort/operators/options do Driver, e customizadores de publisher, permitindo o uso direto do MongoDB Driver quando necessário.

Quatro fluxos abordados neste documento.

Consulta Mongo Geral.

Este é o fluxo inicial em que esta biblioteca começou. As condições e a execução são configuradas na ordem execute* → fields(...) → end() → find/findAll/count/delete/exists/atomicUpdate.

Agregação nativa do Driver.

Para controlar diretamente desde o primeiro estágio do pipeline ou usar a nova funcionalidade de agregação fornecida pelo Driver, usamos o fluxo aggregation().stage(Bson). Estágios como $score e $scoreFusion, que já são fornecidos pelo Driver, podem ser passados sem serem reimplementados pelo DSL.

Atlas Search

Este fluxo foi adicionado ao aplicar o Atlas Search ao projeto sem introduzir um serviço de busca separado. Após search(index), configuramos texto, composto, pontuação, destaque e tokens de sequência.

Pesquisa Vetorial

Este fluxo foi adicionado para conectar a pesquisa de embedding dentro do MongoDB. Configuramos opções de vetor de consulta ou embedding automatizado, ANN/ENN, pré/pós-filtro e opções de embedding aninhadas/array.

Modelo de execução da versão 1.0.0.
text

Separar consultas gerais de Search/Vector é para não ocultar as restrições reais do pipeline do MongoDB. $search e $vectorSearch têm restrições no primeiro estágio, e funcionalidades que exigem controle total do chamador no primeiro estágio podem ser tratadas com aggregation().

Escopo usado em projetos reais

Passamos pares sem condições como null para montar condições de pesquisa dinâmicas por tela.

Separando data e totalCount com PageStream, mantemos o fluxo de processamento em estado de publisher reativo.

Criamos operações seguras contra execuções duplicadas com atomicUpdate().upsertOne().document().setOnInsert(...).

Armazenamos dados coletados e dados de integração externa com bulk upsert com base em ID ou chave de trabalho.

Retornamos os resultados de lookup e a contagem total em um único pipeline com executeLookupAndCount.

Usamos o token de sequência do Atlas Search e a consulta de embedding automatizado do Vector Search.

Os novos estágios de agregação fornecidos pelo Driver são conectados diretamente com aggregation().stage(Bson) ou stage(Bson) de Search/Vector.

Se a atomicidade entre operações DSL for necessária, especificamos o escopo da transação ClientSession com getTxJob(...).

© 2026 Byeolnaerim. Todos os direitos reservados.IntroduçãoPolítica de Privacidade