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
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.
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á.