MongoDB
 sql >> Base de Dados >  >> NoSQL >> MongoDB

Repositórios Spring Data Reactive com MongoDB

1. Introdução


Neste tutorial, veremos como configurar e implementar operações de banco de dados usando Programação Reativa por meio de Spring Data Reactive Repositories com MongoDB.

Veremos os usos básicos do ReactiveCrud Repositório, ReactiveMongoRepository , bem como ReactiveMongoTemplate.

Embora essas implementações usem programação reativa, esse não é o foco principal deste tutorial.

2. Ambiente


Para usar o Reactive MongoDB, precisamos adicionar a dependência ao nosso pom.xml.

Também adicionaremos um MongoDB incorporado para teste:
<dependencies>
    // ...
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-mongodb-reactive</artifactId>
    </dependency>
    <dependency>
        <groupId>de.flapdoodle.embed</groupId>
        <artifactId>de.flapdoodle.embed.mongo</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

3. Configuração


Para ativar o suporte reativo, precisamos usar o @EnableReactiveMongoRepositories juntamente com alguma configuração de infraestrutura:
@EnableReactiveMongoRepositories
public class MongoReactiveApplication
  extends AbstractReactiveMongoConfiguration {

    @Bean
    public MongoClient mongoClient() {
        return MongoClients.create();
    }

    @Override
    protected String getDatabaseName() {
        return "reactive";
    }
}

Observe que o acima seria necessário se estivéssemos usando a instalação autônoma do MongoDB. Mas, como estamos usando o Spring Boot com MongoDB incorporado em nosso exemplo, a configuração acima não é necessária.

4. Criando um Documento


Para os exemplos abaixo, vamos criar uma Conta class e anote com @Document para usá-lo nas operações do banco de dados:
@Document
public class Account {
 
    @Id
    private String id;
    private String owner;
    private Double value;
 
    // getters and setters
}

5. Usando repositórios reativos


Já estamos familiarizados com o modelo de programação de repositórios, com os métodos CRUD já definidos além de suporte para algumas outras coisas comuns também.

Agora com o modelo Reativo, obtemos o mesmo conjunto de métodos e especificações, exceto que vamos lidar com os resultados e parâmetros de forma reativa.

5.1. ReactiveCrudRepository


Podemos usar este repositório da mesma forma que o CrudRepository de bloqueio :
@Repository
public interface AccountCrudRepository 
  extends ReactiveCrudRepository<Account, String> {
 
    Flux<Account> findAllByValue(String value);
    Mono<Account> findFirstByOwner(Mono<String> owner);
}

Podemos passar diferentes tipos de argumentos como simples (String ), encapsulado (Opcional , Transmitir ), ou reativo (Mono , Fluxo ) como podemos ver no findFirstByOwner() método.

5.2. ReactiveMongoRepository


Há também o ReactiveMongoRepository interface, que herda de ReactiveCrudRepository e adiciona alguns novos métodos de consulta:
@Repository
public interface AccountReactiveRepository 
  extends ReactiveMongoRepository<Account, String> { }

Usando o ReactiveMongoRepository , podemos consultar por exemplo:
Flux<Account> accountFlux = repository
  .findAll(Example.of(new Account(null, "owner", null)));

Como resultado, obteremos todas as Contas que é o mesmo que o exemplo passado.

Com nossos repositórios criados, eles já possuem métodos definidos para realizar algumas operações de banco de dados que não precisamos implementar:
Mono<Account> accountMono 
  = repository.save(new Account(null, "owner", 12.3));
Mono<Account> accountMono2 = repository
  .findById("123456");

5.3. RxJava2CrudRepository


Com RxJava2CrudRepository, temos o mesmo comportamento do ReactiveCrudRepository, mas com os resultados e tipos de parâmetros de RxJava :
@Repository
public interface AccountRxJavaRepository 
  extends RxJava2CrudRepository<Account, String> {
 
    Observable<Account> findAllByValue(Double value);
    Single<Account> findFirstByOwner(Single<String> owner);
}

5.4. Testando nossas operações básicas


Para testar nossos métodos de repositório, usaremos o assinante de teste:
@Test
public void givenValue_whenFindAllByValue_thenFindAccount() {
    repository.save(new Account(null, "Bill", 12.3)).block();
    Flux<Account> accountFlux = repository.findAllByValue(12.3);

    StepVerifier
      .create(accountFlux)
      .assertNext(account -> {
          assertEquals("Bill", account.getOwner());
          assertEquals(Double.valueOf(12.3) , account.getValue());
          assertNotNull(account.getId());
      })
      .expectComplete()
      .verify();
}

@Test
public void givenOwner_whenFindFirstByOwner_thenFindAccount() {
    repository.save(new Account(null, "Bill", 12.3)).block();
    Mono<Account> accountMono = repository
      .findFirstByOwner(Mono.just("Bill"));

    StepVerifier
      .create(accountMono)
      .assertNext(account -> {
          assertEquals("Bill", account.getOwner());
          assertEquals(Double.valueOf(12.3) , account.getValue());
          assertNotNull(account.getId());
      })
      .expectComplete()
      .verify();
}

@Test
public void givenAccount_whenSave_thenSaveAccount() {
    Mono<Account> accountMono = repository.save(new Account(null, "Bill", 12.3));

    StepVerifier
      .create(accountMono)
      .assertNext(account -> assertNotNull(account.getId()))
      .expectComplete()
      .verify();
}

6. ReactiveMongoTemplate


Além da abordagem de repositórios, temos oReactiveMongoTemplate .

Primeiro, precisamos registrar o ReactiveMongoTemplate como feijão:
@Configuration
public class ReactiveMongoConfig {
 
    @Autowired
    MongoClient mongoClient;

    @Bean
    public ReactiveMongoTemplate reactiveMongoTemplate() {
        return new ReactiveMongoTemplate(mongoClient, "test");
    }
}

E então, podemos injetar este bean em nosso serviço para realizar as operações do banco de dados:
@Service
public class AccountTemplateOperations {
 
    @Autowired
    ReactiveMongoTemplate template;

    public Mono<Account> findById(String id) {
        return template.findById(id, Account.class);
    }
 
    public Flux<Account> findAll() {
        return template.findAll(Account.class);
    } 
    public Mono<Account> save(Mono<Account> account) {
        return template.save(account);
    }
}

ReactiveMongoTemplate também tem uma série de métodos que não se relacionam com o domínio que temos, você pode conferir na documentação.