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

Introdução ao Spring Data MongoDB

1. Visão geral


Este artigo será uma introdução rápida e prática ao Spring Data MongoDB.

Veremos o básico usando o MongoTemplate bem como MongoRepository , com exemplos práticos para ilustrar cada operação.

Leitura adicional:

Suporte geoespacial no MongoDB

Veja como armazenar, indexar e pesquisar dados geoespaciais com o MongoDBLeia mais →

Teste de integração Spring Boot com MongoDB incorporado

Aprenda a usar a solução MongoDB incorporada do Flapdoodle junto com o Spring Boot para executar testes de integração do MongoDB sem problemas.Leia mais →

2. MongoTemplate eMongoRepository


O MongoTemplate segue o padrão de modelo padrão no Spring e fornece uma API básica pronta para uso para o mecanismo de persistência subjacente.

O repositório segue a abordagem centrada no Spring Data e vem com operações de API mais flexíveis e complexas, com base nos padrões de acesso bem conhecidos em todos os projetos Spring Data.

Para ambos, precisamos começar definindo a dependência — por exemplo, no pom.xml , com Maven:
<dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-mongodb</artifactId>
    <version>3.0.3.RELEASE</version>
</dependency>

Para verificar se alguma nova versão da biblioteca foi lançada, acompanhe os lançamentos aqui.

3. Configuração para MongoTemplate

3.1. Configuração XML


Vamos começar com a configuração XML simples para o modelo Mongo:
<mongo:mongo-client id="mongoClient" host="localhost" />
<mongo:db-factory id="mongoDbFactory" dbname="test" mongo-client-ref="mongoClient" />

Primeiro precisamos definir o bean de fábrica responsável por criar instâncias do Mongo.

Em seguida, precisamos realmente definir (e configurar) o bean de modelo:
<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate"> 
    <constructor-arg ref="mongoDbFactory"/> 
</bean>

E, finalmente, precisamos definir um pós-processador para traduzir qualquer MongoExceptions lançado em @Repository classes anotadas:
<bean class=
  "org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>

3.2. Configuração Java


Vamos agora criar uma configuração semelhante usando a configuração Java estendendo a classe base para a configuração do MongoDB AbstractMongoConfiguration :
@Configuration
public class MongoConfig extends AbstractMongoClientConfiguration {
 
    @Override
    protected String getDatabaseName() {
        return "test";
    }
 
    @Override
    public MongoClient mongoClient() {
        ConnectionString connectionString = new ConnectionString("mongodb://localhost:27017/test");
        MongoClientSettings mongoClientSettings = MongoClientSettings.builder()
            .applyConnectionString(connectionString)
            .build();
        
        return MongoClients.create(mongoClientSettings);
    }
 
    @Override
    public Collection getMappingBasePackages() {
        return Collections.singleton("com.baeldung");
    }
}

Observe que não precisamos definir MongoTemplate bean na configuração anterior, pois já está definido em AbstractMongoClientConfiguration .

Também podemos usar nossa configuração do zero sem estender AbstractMongoClientConfiguration :
@Configuration
public class SimpleMongoConfig {
 
    @Bean
    public MongoClient mongo() {
        ConnectionString connectionString = new ConnectionString("mongodb://localhost:27017/test");
        MongoClientSettings mongoClientSettings = MongoClientSettings.builder()
          .applyConnectionString(connectionString)
          .build();
        
        return MongoClients.create(mongoClientSettings);
    }

    @Bean
    public MongoTemplate mongoTemplate() throws Exception {
        return new MongoTemplate(mongo(), "test");
    }
}

4. Configuração para MongoRepository

4.1. Configuração XML


Para fazer uso de repositórios personalizados (estendendo o MongoRepository ), precisamos continuar a configuração da seção 3.1. e configure os repositórios:
<mongo:repositories 
  base-package="com.baeldung.repository" mongo-template-ref="mongoTemplate"/>

4.2. Configuração Java


Da mesma forma, desenvolveremos a configuração que já criamos na seção 3.2. e adicione uma nova anotação à mistura:
@EnableMongoRepositories(basePackages = "com.baeldung.repository")

4.3. Crie o repositório


Após a configuração, precisamos criar um repositório — estendendo o MongoRepository existente interface:
public interface UserRepository extends MongoRepository<User, String> {
    // 
}

Agora podemos conectar automaticamente este UserRepository e use operações do MongoRepository ou adicionar operações personalizadas.

5. Usando MongoTemplate

5.1. Inserir


Vamos começar com a operação de inserção, bem como um banco de dados vazio:
{
}

Agora, se inserirmos um novo usuário:
User user = new User();
user.setName("Jon");
mongoTemplate.insert(user, "user");

o banco de dados ficará assim:
{
    "_id" : ObjectId("55b4fda5830b550a8c2ca25a"),
    "_class" : "com.baeldung.model.User",
    "name" : "Jon"
}

5.2. Salvar – Inserir


Osalvar A operação tem uma semântica de salvar ou atualizar:se um id estiver presente, ele executa uma atualização e, se não, ele faz uma inserção.

Vejamos a primeira semântica — a inserção.

Aqui está o estado inicial do banco de dados:
{
}

Quando agora salvamos um novo usuário:
User user = new User();
user.setName("Albert"); 
mongoTemplate.save(user, "user");

a entidade será inserida no banco de dados:
{
    "_id" : ObjectId("55b52bb7830b8c9b544b6ad5"),
    "_class" : "com.baeldung.model.User",
    "name" : "Albert"
}

Em seguida, veremos a mesma operação — salvar — com semântica de atualização.

5.3. Salvar – Atualizar


Vamos agora ver salvar com semântica de atualização, operando em uma entidade existente:
{
    "_id" : ObjectId("55b52bb7830b8c9b544b6ad5"),
    "_class" : "com.baeldung.model.User",
    "name" : "Jack"
}

Quando salvamos o usuário existente, vamos atualizá-lo:
user = mongoTemplate.findOne(
  Query.query(Criteria.where("name").is("Jack")), User.class);
user.setName("Jim");
mongoTemplate.save(user, "user");

O banco de dados ficará assim:
{
    "_id" : ObjectId("55b52bb7830b8c9b544b6ad5"),
    "_class" : "com.baeldung.model.User",
    "name" : "Jim"
}

Podemos ver que neste exemplo em particular, salvar usa a semântica de atualizar porque usamos um objeto com determinado _id .

5.4. Atualizar primeiro


atualizar primeiro atualiza o primeiro documento que corresponde à consulta.

Vamos começar com o estado inicial do banco de dados:
[
    {
        "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
        "_class" : "com.baeldung.model.User",
        "name" : "Alex"
    },
    {
        "_id" : ObjectId("55b5ffa5511fee0e45ed614c"),
        "_class" : "com.baeldung.model.User",
        "name" : "Alex"
    }
]

Quando agora executamos o updateFirst :
Query query = new Query();
query.addCriteria(Criteria.where("name").is("Alex"));
Update update = new Update();
update.set("name", "James");
mongoTemplate.updateFirst(query, update, User.class);

apenas a primeira entrada será atualizada:
[
    {
        "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
        "_class" : "com.baeldung.model.User",
        "name" : "James"
    },
    {
        "_id" : ObjectId("55b5ffa5511fee0e45ed614c"),
        "_class" : "com.baeldung.model.User",
        "name" : "Alex"
    }
]

5.5. AtualizarMulti


AtualizarMulti atualiza todos os documentos que correspondem à consulta fornecida.

Primeiro, aqui está o estado do banco de dados antes de fazer o updateMulti :
[
    {
        "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
        "_class" : "com.baeldung.model.User",
        "name" : "Eugen"
    },
    {
        "_id" : ObjectId("55b5ffa5511fee0e45ed614c"),
        "_class" : "com.baeldung.model.User",
        "name" : "Eugen"
    }
]

Agora vamos executar o updateMulti Operação:
Query query = new Query();
query.addCriteria(Criteria.where("name").is("Eugen"));
Update update = new Update();
update.set("name", "Victor");
mongoTemplate.updateMulti(query, update, User.class);

Ambos os objetos existentes serão atualizados no banco de dados:
[
    {
        "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
        "_class" : "com.baeldung.model.User",
        "name" : "Victor"
    },
    {
        "_id" : ObjectId("55b5ffa5511fee0e45ed614c"),
        "_class" : "com.baeldung.model.User",
        "name" : "Victor"
    }
]

5.6. Localizar e modificar


Esta operação funciona como updateMulti , mas retorna o objeto antes de ser modificado.

Primeiro, este é o estado do banco de dados antes de chamar findAndModify :
{
    "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
    "_class" : "com.baeldung.model.User",
    "name" : "Markus"
}

Vejamos o código de operação real:
Query query = new Query();
query.addCriteria(Criteria.where("name").is("Markus"));
Update update = new Update();
update.set("name", "Nick");
User user = mongoTemplate.findAndModify(query, update, User.class);

O objeto de usuário retornado tem os mesmos valores que o estado inicial no banco de dados.

No entanto, este é o novo estado no banco de dados:
{
    "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
    "_class" : "com.baeldung.model.User",
    "name" : "Nick"
}

5.7. Upsert


O sert funciona na semântica encontrar e modificar else create :se o documento for compatível, atualize-o ou crie um novo documento combinando a consulta e o objeto de atualização.

Vamos começar com o estado inicial do banco de dados:
{
    "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
    "_class" : "com.baeldung.model.User",
    "name" : "Markus"
}

Agora vamos executar o upsert :
Query query = new Query();
query.addCriteria(Criteria.where("name").is("Markus"));
Update update = new Update();
update.set("name", "Nick");
mongoTemplate.upsert(query, update, User.class);

Aqui está o estado do banco de dados após a operação:
{
    "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
    "_class" : "com.baeldung.model.User",
    "name" : "Nick"
}

5.8. Remover


Veremos o estado do banco de dados antes de chamar remove :
{
    "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
    "_class" : "com.baeldung.model.User",
    "name" : "Benn"
}

Agora vamos executar remover :
mongoTemplate.remove(user, "user");

O resultado será o esperado:
{
}

6. Usando o MongoRepository

6.1. Inserir


Primeiro, veremos o estado do banco de dados antes de executar o inserir :
{
}

Agora vamos inserir um novo usuário:
User user = new User();
user.setName("Jon");
userRepository.insert(user);

E aqui está o estado final do banco de dados:
{
    "_id" : ObjectId("55b4fda5830b550a8c2ca25a"),
    "_class" : "com.baeldung.model.User",
    "name" : "Jon"
}

Observe como a operação funciona da mesma forma que inserir no MongoTemplate API.

6.2. Salvar Inserir


Da mesma forma, salvar funciona da mesma forma que salvar operação no MongoTemplate API.

Vamos começar analisando a semântica de inserção da operação.

Aqui está o estado inicial do banco de dados:
{
}

Agora executamos o salvar Operação:
User user = new User();
user.setName("Aaron");
userRepository.save(user);

Isso resulta na adição do usuário ao banco de dados:
{
    "_id" : ObjectId("55b52bb7830b8c9b544b6ad5"),
    "_class" : "com.baeldung.model.User",
    "name" : "Aaron"
}

Observe novamente como salvar funciona com inserir semântica porque estamos inserindo um novo objeto.

6.3. Salvar Atualizar


Vejamos agora a mesma operação, mas com atualizar semântica.

Primeiro, aqui está o estado do banco de dados antes de executar o novo salvar :
{
    "_id" : ObjectId("55b52bb7830b8c9b544b6ad5"),
    "_class" : "com.baeldung.model.User",
    "name" : "Jack"81*6
}

Agora executamos a operação:
user = mongoTemplate.findOne(
  Query.query(Criteria.where("name").is("Jack")), User.class);
user.setName("Jim");
userRepository.save(user);

Finalmente, aqui está o estado do banco de dados:
{
    "_id" : ObjectId("55b52bb7830b8c9b544b6ad5"),
    "_class" : "com.baeldung.model.User",
    "name" : "Jim"
}

Observe novamente como salvar funciona com atualização semântica porque estamos usando um objeto existente.

6.4. Excluir


Aqui está o estado do banco de dados antes de chamar delete :
{
    "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
    "_class" : "com.baeldung.model.User",
    "name" : "Benn"
}

Vamos executar excluir :
userRepository.delete(user);

E aqui está o nosso resultado:
{
}

6.5. Encontre um


Em seguida, este é o estado do banco de dados quando findOne é chamado:
{
    "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
    "_class" : "com.baeldung.model.User",
    "name" : "Chris"
}

Vamos agora executar o findOne :
userRepository.findOne(user.getId())

E o resultado retornará os dados existentes:
{
    "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
    "_class" : "com.baeldung.model.User",
    "name" : "Chris"
}

6.6. Existe


O estado do banco de dados antes de chamar existe :
{
    "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
    "_class" : "com.baeldung.model.User",
    "name" : "Harris"
}

Agora vamos executar exists , que obviamente retornará true :
boolean isExists = userRepository.exists(user.getId());

6.7. Localizar tudo Com Classificar


O estado do banco de dados antes de chamar findAll :
[
    {
        "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
        "_class" : "com.baeldung.model.User",
        "name" : "Brendan"
    },
    {
        "_id" : ObjectId("67b5ffa5511fee0e45ed614b"),
        "_class" : "com.baeldung.model.User",
        "name" : "Adam"
    }
]

Vamos agora executar findAll com Classificar :
List<User> users = userRepository.findAll(Sort.by(Sort.Direction.ASC, "name"));

O resultado será classificado por nome em ordem crescente :
[
    {
        "_id" : ObjectId("67b5ffa5511fee0e45ed614b"),
        "_class" : "com.baeldung.model.User",
        "name" : "Adam"
    },
    {
        "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
        "_class" : "com.baeldung.model.User",
        "name" : "Brendan"
    }
]

6.8. Localizar tudo Com Paginável


O estado do banco de dados antes de chamar findAll :
[
    {
        "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
        "_class" : "com.baeldung.model.User",
        "name" : "Brendan"
    },
    {
        "_id" : ObjectId("67b5ffa5511fee0e45ed614b"),
        "_class" : "com.baeldung.model.User",
        "name" : "Adam"
    }
]

Vamos agora executar findAll com uma solicitação de paginação:
Pageable pageableRequest = PageRequest.of(0, 1);
Page<User> page = userRepository.findAll(pageableRequest);
List<User> users = pages.getContent();

Os usuários resultantes list será apenas um usuário:

{
    "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
    "_class" : "com.baeldung.model.User",
    "name" : "Brendan"
}

7. Anotações


Por fim, vamos também examinar as anotações simples que o Spring Data usa para conduzir essas operações de API.

O nível de campo @Id anotação pode decorar qualquer tipo, incluindo longa e cadeia :
@Id
private String id;

Se o valor do @Id campo não é nulo, é armazenado no banco de dados como está; caso contrário, o conversor assumirá que queremos armazenar um ObjectId no banco de dados (ou ObjectId , Sequência ou BigInteger trabalhar).

Em seguida, examinaremos @Document :
@Document
public class User {
    //
}

Esta anotação simplesmente marca uma classe como sendo um objeto de domínio que precisa ser persistido no banco de dados, além de nos permitir escolher o nome da coleção a ser usada.