Spring Data MongoDB - Índices, anotações e conversores
1. Visão geral
Este tutorial irá explorar alguns dos principais recursos do Spring Data MongoDB - indexação, anotações comuns e conversores.
2. Índices
2.1. @Indexed
Esta anotaçãomarks the field as indexed no MongoDB:
@QueryEntity
@Document
public class User {
@Indexed
private String name;
...
}
Agora que o camponame está indexado - vamos dar uma olhada nos índices no MongoDB:
db.user.getIndexes();
Aqui está o que temos no nível do banco de dados:
[
{
"v" : 1,
"key" : {
"_id" : 1
},
"name" : "_id_",
"ns" : "test.user"
},
{
"v" : 1,
"key" : {
"name" : 1
},
"name" : "name",
"ns" : "test.user"
}
]
Como você pode ver, temos dois índices - um deles é_id - que foi criado por padrão devido à anotação@Id ethe second one is our name field.
2.2. Crie um índice programaticamente
Também podemos criar um índice programaticamente:
mongoOps.indexOps(User.class).
ensureIndex(new Index().on("name", Direction.ASC));
Agora criamos um índice para o camponame e o resultado será o mesmo da seção anterior.
2.3. Índices Compostos
O MongoDB suporta índices compostos, onde uma única estrutura de índice mantém referências a vários campos.
Vejamos um exemplo rápido usando índices compostos:
@QueryEntity
@Document
@CompoundIndexes({
@CompoundIndex(name = "email_age", def = "{'email.id' : 1, 'age': 1}")
})
public class User {
//
}
Criamos um índice composto com os camposemaileage. Vamos agora verificar os índices reais:
{
"v" : 1,
"key" : {
"email.id" : 1,
"age" : 1
},
"name" : "email_age",
"ns" : "test.user"
}
Observe que um campoDBRef não pode ser marcado com@Index - esse campo só pode ser parte de um índice composto.
3. Anotações Comuns
3.1 @Transient
Como seria de esperar, esta anotação simples exclui a persistência do campo no banco de dados:
public class User {
@Transient
private Integer yearOfBirth;
// standard getter and setter
}
Vamos inserir o usuário com o campo de configuraçãoyearOfBirth:
User user = new User();
user.setName("Alex");
user.setYearOfBirth(1985);
mongoTemplate.insert(user);
Agora, se olharmos o estado do banco de dados, vemos que oyearOfBirth arquivado não foi salvo:
{
"_id" : ObjectId("55d8b30f758fd3c9f374499b"),
"name" : "Alex",
"age" : null
}
Portanto, se consultarmos e verificarmos:
mongoTemplate.findOne(Query.query(Criteria.where("name").is("Alex")), User.class).getYearOfBirth()
O resultado seránull.
3.2. @Field
@Field indica a chave a ser usada para o campo no documento JSON:
@Field("email")
private EmailAddress emailAddress;
AgoraemailAddress será salvo no banco de dados usando a chaveemail:
User user = new User();
user.setName("Brendan");
EmailAddress emailAddress = new EmailAddress();
emailAddress.setValue("[email protected]");
user.setEmailAddress(emailAddress);
mongoTemplate.insert(user);
E o estado do banco de dados:
{
"_id" : ObjectId("55d076d80bad441ed114419d"),
"name" : "Brendan",
"age" : null,
"email" : {
"value" : "[email protected]"
}
}
3.3. @PersistenceConstructor e@Value
@PersistenceConstructor marca um construtor, mesmo aquele que é protegido por pacote, para ser o construtor primário usado pela lógica de persistência. Os argumentos do construtor são mapeados por nome para os valores-chave nosDBObject recuperados.
Vejamos este construtor para nossa classeUser:
@PersistenceConstructor
public User(String name, @Value("#root.age ?: 0") Integer age, EmailAddress emailAddress) {
this.name = name;
this.age = age;
this.emailAddress = emailAddress;
}
Observe o uso da anotação Spring@Value padrão aqui. É com a ajuda desta anotação que podemos usar as Expressões Spring para transformar o valor de uma chave recuperado do banco de dados antes de ser usado para construir um objeto de domínio. Esse é um recurso muito poderoso e altamente útil aqui.
Em nosso exemplo, seage não estiver definido, ele será definido como0 por padrão.
Vamos agora ver como funciona:
User user = new User();
user.setName("Alex");
mongoTemplate.insert(user);
Nosso banco de dados será:
{
"_id" : ObjectId("55d074ca0bad45f744a71318"),
"name" : "Alex",
"age" : null
}
Portanto, o campoage énull, mas quando consultamos o documento e recuperamosage:
mongoTemplate.findOne(Query.query(Criteria.where("name").is("Alex")), User.class).getAge();
O resultado será 0.
4. Conversores
Vamos agora dar uma olhada em outro recurso muito útil no Spring Data MongoDB - conversores, e especificamente noMongoConverter.
Isso é usado para lidar com o mapeamento de todos os tipos Java paraDBObjects ao armazenar e consultar esses objetos.
Temos duas opções - podemos trabalhar comMappingMongoConverter – ouSimpleMongoConverter em versões anteriores (isso foi descontinuado no Spring Data MongoDB M3 e sua funcionalidade foi movida paraMappingMongoConverter).
Ou podemos escrever nosso próprio conversor personalizado. Para fazer isso, precisaríamos implementar a interfaceConverter e registrar a implementação emMongoConfig.
Vejamosa quick example. Como você viu em algumas das saídas JSON aqui, todos os objetos salvos em um banco de dados têm o campo_class que é salvo automaticamente. Se, no entanto, quisermos pular esse campo específico durante a persistência, podemos fazer isso usandoMappingMongoConverter.
Primeiro - aqui está a implementação do conversor personalizado:
@Component
public class UserWriterConverter implements Converter {
@Override
public DBObject convert(User user) {
DBObject dbObject = new BasicDBObject();
dbObject.put("name", user.getName());
dbObject.put("age", user.getAge());
if (user.getEmailAddress() != null) {
DBObject emailDbObject = new BasicDBObject();
emailDbObject.put("value", user.getEmailAddress().getValue());
dbObject.put("email", emailDbObject);
}
dbObject.removeField("_class");
return dbObject;
}
}
Observe como podemos atingir facilmente a meta de não persistir_class removendo especificamente o campo diretamente aqui.
Agora precisamos registrar o conversor personalizado:
private List> converters = new ArrayList>();
@Override
public MongoCustomConversions customConversions() {
converters.add(new UserWriterConverter());
return new MongoCustomConversions(converters);
}
Obviamente, também podemos obter o mesmo resultado com a configuração XML, se precisarmos:
Agora, quando salvamos um novo usuário:
User user = new User();
user.setName("Chris");
mongoOps.insert(user);
O documento resultante no banco de dados não contém mais as informações da classe:
{
"_id" : ObjectId("55cf09790bad4394db84b853"),
"name" : "Chris",
"age" : null
}
5. Conclusão
Neste tutorial, cobrimos alguns conceitos básicos de trabalho com Spring Data MongoDB - indexação, anotações comuns e conversores.
A implementação de todos esses exemplos e fragmentos de códigocan be found inmy github project - este é um projeto baseado em Eclipse, portanto, deve ser fácil de importar e executar como está.