Introdução ao Spring Data MongoDB

Introdução ao Spring Data MongoDB

1. Visão geral

Este artigo será umintroduction to Spring Data MongoDB rápido e prático.

Vamos repassar o básico usandoMongoTemplate, bem comoMongoRepository, usando exemplos práticos para ilustrar cada operação.

Leitura adicional:

Suporte geoespacial no MongoDB

Veja como armazenar, indexar e pesquisar dados geoespaciais com o MongoDB

Read more

Teste de integração de inicialização com o 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.

Read more

2. MongoTemplateand MongoRepository

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

The repository segue a abordagem centrada em 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, empom.xml, com Maven:


    org.springframework.data
    spring-data-mongodb
    2.1.9.RELEASE



    org.springframework.data
    spring-data-releasetrain
    Lovelace-SR9
    pom
    import

Para verificar se alguma nova versão da biblioteca foi lançada -track the releases here.

3. Configuração paraMongoTemplate

3.1. Configuração XML

Vamos começar com a configuração XML simples para o modelo Mongo:


Primeiro, precisamos definir o bean de fábrica responsável pela criação de instâncias do Mongo.

Em seguida - precisamos realmente definir (e configurar) o bean de modelo:


    

E, finalmente, precisamos definir um pós-processador para traduzir qualquerMongoExceptions lançado nas classes anotadas de@Repository:

3.2. Configuração Java

Vamos agora criar uma configuração semelhante usando a configuração Java, estendendo a classe base para a configuraçãoAbstractMongoConfiguration do MongoDB:

@Configuration
public class MongoConfig extends AbstractMongoConfiguration {

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

    @Override
    public MongoClient mongoClient() {
        return new MongoClient("127.0.0.1", 27017);
    }

    @Override
    protected String getMappingBasePackage() {
        return "org.example";
    }
}

Nota: Não precisamos definir o beanMongoTemplate na configuração anterior, pois já está definido emAbstractMongoConfiguration

Também podemos usar nossa configuração do zero sem estenderAbstractMongoConfiguration - da seguinte maneira:

@Configuration
public class SimpleMongoConfig {

    @Bean
    public MongoClient mongo() {
        return new MongoClient("localhost");
    }

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

4. Configuração paraMongoRepository

4.1. Configuração XML

Para fazer uso de repositórios personalizados (estendendoMongoRepository) - precisamos continuar a configuração da seção 3.1 e definir os repositórios:

4.2. Configuração Java

Da mesma forma, vamos construir sobre a configuração que já criamos na seção 3.2 e adicionar uma nova anotação à combinação:

@EnableMongoRepositories(basePackages = "org.example.repository")

4.3. Crie o Repositório

Agora, após a configuração, precisamos criar um repositório - estendendo a interfaceMongoRepository existente:

public interface UserRepository extends MongoRepository {
    //
}

Agora podemos conectar automaticamente esteUserRepositorye usar operações deMongoRepository ou adicionar operações personalizadas.

5. UsandoMongoTemplate

5.1. Insert

Vamos começar com a operação de inserção; vamos começar também com 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" : "org.example.model.User",
    "name" : "Jon"
}

5.2. Save – Insert

A operaçãosave tem semântica salvar ou atualizar: se um id estiver presente, ele executa uma atualização, 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 somossave 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" : "org.example.model.User",
    "name" : "Albert"
}

A seguir, veremos a mesma operação -save - com semântica de atualização.

5.3. Save – Update

Vejamos agorasave com semântica de atualização, operando em uma entidade existente:

{
    "_id" : ObjectId("55b52bb7830b8c9b544b6ad5"),
    "_class" : "org.example.model.User",
    "name" : "Jack"
}

Agora, quandosave 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" : "org.example.model.User",
    "name" : "Jim"
}

Como você pode ver, neste exemplo específico,save usa a semântica deupdate, porque usamos um objeto com determinado_id.

5.4. UpdateFirst

updateFirst atualiza o primeiro documento que corresponde à consulta.

Vamos começar com o estado inicial do banco de dados:

[
    {
        "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
        "_class" : "org.example.model.User",
        "name" : "Alex"
    },
    {
        "_id" : ObjectId("55b5ffa5511fee0e45ed614c"),
        "_class" : "org.example.model.User",
        "name" : "Alex"
    }
]

Quando agora executamos oupdateFirst:

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);

Somente a primeira entrada será atualizada:

[
    {
        "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
        "_class" : "org.example.model.User",
        "name" : "James"
    },
    {
        "_id" : ObjectId("55b5ffa5511fee0e45ed614c"),
        "_class" : "org.example.model.User",
        "name" : "Alex"
    }
]

5.5. UpdateMulti

UpdateMultiupdates all document that matches the given query.

Primeiro - aqui está o estado do banco de dados antes de fazer oupdateMulti:

[
    {
        "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
        "_class" : "org.example.model.User",
        "name" : "Eugen"
    },
    {
        "_id" : ObjectId("55b5ffa5511fee0e45ed614c"),
        "_class" : "org.example.model.User",
        "name" : "Eugen"
    }
]

Agora, vamos agora executar a operaçãoupdateMulti:

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);

Os dois objetos existentes serão atualizados no banco de dados:

[
    {
        "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
        "_class" : "org.example.model.User",
        "name" : "Victor"
    },
    {
        "_id" : ObjectId("55b5ffa5511fee0e45ed614c"),
        "_class" : "org.example.model.User",
        "name" : "Victor"
    }
]

5.6. FindAndModify

Esta operação funciona comoupdateMulti, mas éreturns the object before it was modified.

Primeiro - o estado do banco de dados antes de chamarfindAndModify:

{
    "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
    "_class" : "org.example.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);

Ouser object retornado possui os mesmos valores que o estado inicial no banco de dados.

No entanto, o novo estado no banco de dados é:

{
    "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
    "_class" : "org.example.model.User",
    "name" : "Nick"
}

5.7. Upsert

Os trabalhos deupsert operam nofind and modify else create semantics: se o documento for compatível, atualize-o, caso contrário, crie um novo documento combinando o objeto de consulta e atualização.

Vamos começar com o estado inicial do banco de dados:

{
    "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
    "_class" : "org.example.model.User",
    "name" : "Markus"
}

Agora - vamos executar oupsert:

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);

Este é o estado do banco de dados após a operação:

{
    "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
    "_class" : "org.example.model.User",
    "name" : "Nick"
}

5.8. Remove

O estado do banco de dados antes de chamarremove:

{
    "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
    "_class" : "org.example.model.User",
    "name" : "Benn"
}

Vamos agora executarremove:

mongoTemplate.remove(user, "user");

O resultado será o esperado:

{
}

6. UsandoMongoRepository

6.1. Insert

Primeiro - o estado do banco de dados antes de executar oinsert:

{
}

Agora, quando inserimos um novo usuário:

User user = new User();
user.setName("Jon");
userRepository.insert(user);

Este é o estado final do banco de dados:

{
    "_id" : ObjectId("55b4fda5830b550a8c2ca25a"),
    "_class" : "org.example.model.User",
    "name" : "Jon"
}

Observe como a operação funciona da mesma forma queinsert na APIMongoTemplate.

6.2. Save -Insert

Da mesma forma -save funciona da mesma forma que a operaçãosave na APIMongoTemplate.

Vamos começar observandothe insert semantics da operação; aqui está o estado inicial do banco de dados:

{
}

Agora - executamos a operaçãosave:

User user = new User();
user.setName("Aaron");
userRepository.save(user);

Isso resulta no usuário sendo adicionado ao banco de dados:

{
    "_id" : ObjectId("55b52bb7830b8c9b544b6ad5"),
    "_class" : "org.example.model.User",
    "name" : "Aaron"
}

Observe novamente como, neste exemplo,save funciona com a semânticainsert, porque estamos inserindo um novo objeto.

6.3. Save -Update

Vejamos agora a mesma operação, mas comupdate semantics.

Primeiro - aqui está o estado do banco de dados antes de executar o novosave:

{
    "_id" : ObjectId("55b52bb7830b8c9b544b6ad5"),
    "_class" : "org.example.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" : "org.example.model.User",
    "name" : "Jim"
}

Observe novamente como, neste exemplo,save funciona com a semânticaupdate, porque estamos usando um objeto existente.

6.4. Delete

O estado do banco de dados antes de chamardelete:

{
    "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
    "_class" : "org.example.model.User",
    "name" : "Benn"
}

Vamos executardelete:

userRepository.delete(user);

O resultado será simplesmente:

{
}

6.5. FindOne

O estado do banco de dados quandofindOne é chamado:

{
    "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
    "_class" : "org.example.model.User",
    "name" : "Chris"
}

Vamos agora executar ofindOne:

userRepository.findOne(user.getId())

O resultado que retornará os dados existentes:

{
    "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
    "_class" : "org.example.model.User",
    "name" : "Chris"
}

6.6. Exists

O estado do banco de dados antes de chamarexists:

{
    "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
    "_class" : "org.example.model.User",
    "name" : "Harris"
}

Agora, vamos executarexists:

boolean isExists = userRepository.exists(user.getId());

Que, obviamente, retornarátrue.

6.7. FindAll #with[.pl-en] Sort#

O estado do banco de dados antes de chamarfindAll:

[
    {
        "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
        "_class" : "org.example.model.User",
        "name" : "Brendan"
    },
    {
       "_id" : ObjectId("67b5ffa5511fee0e45ed614b"),
       "_class" : "org.example.model.User",
       "name" : "Adam"
    }
]

Vamos agora executarfindAll comSort:

List users = userRepository.findAll(new Sort(Sort.Direction.ASC, "name"));

O resultado serásorted by name in ascending order:

[
    {
        "_id" : ObjectId("67b5ffa5511fee0e45ed614b"),
        "_class" : "org.example.model.User",
        "name" : "Adam"
    },
    {
        "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
        "_class" : "org.example.model.User",
        "name" : "Brendan"
    }
]

6.8. FindAll #with[.pl-en] Pageable #

O estado do banco de dados antes de chamarfindAll:

[
    {
        "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
        "_class" : "org.example.model.User",
        "name" : "Brendan"
    },
    {
        "_id" : ObjectId("67b5ffa5511fee0e45ed614b"),
        "_class" : "org.example.model.User",
        "name" : "Adam"
    }
]

Vamos agora executarfindAll com uma solicitação de paginação:

Pageable pageableRequest = PageRequest.of(0, 1);
Page page = userRepository.findAll(pageableRequest);
List users = pages.getContent();

A listausers resultante será apenas um usuário: __

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

7. Anotações

Finalmente, vamos examinar as anotações simples que Spring Data usa para conduzir essas operações de API.

@Id
private String id;

A anotação de nível de campo@Id pode decorar qualquer tipo, incluindolongestring.

Se o valor do campo@Id não for nulo, ele é armazenado no banco de dados como está; caso contrário, o conversor assumirá que você deseja armazenar umObjectId no banco de dados (trabalhoObjectId, String ouBigInteger).

Próximo -@Document:

@Document
public class User {
    //
}

Essa anotação simplesmentemarks a class as being a domain object que precisa ser persistida no banco de dados, além de nos permitir escolher o nome da coleção a ser usada.

8. Conclusão

Este artigo foi uma introdução rápida, mas abrangente, ao uso do MongoDB com Spring Data, tanto por meio da APIMongoTemplate quanto usandoMongoRepository.

A implementação de todos esses exemplos e trechos de códigocan be foundover on Github - este é um projeto baseado em Maven, portanto, deve ser fácil de importar e executar como está.