Весенние данные MongoDB – Индексы, Аннотации и преобразователи
1. Обзор
В этом учебнике мы изумим некоторые основные особенности Spring Data MongoDB – индексирование, общие аннотации и преобразователи.
2. Индексы
2.1. @Indexed
Это аннотация отмечает поле как индексированную в МонгоДБ:
@QueryEntity @Document public class User { @Indexed private String name; ... }
Теперь, когда имя поле индексировано – давайте посмотрим на индексы в оболочке MongoDB:
db.user.getIndexes();
Вот что мы получаем:
[ { "v" : 1, "key" : { "_id" : 1 }, "name" : "_id_", "ns" : "test.user" } ]
Мы можем быть удивлены, что нет никаких признаков имя поле в любом месте!
Это потому, что, по данным Spring Data MongoDB 3.0 автоматическое создание индекса отключено по умолчанию .
Однако мы можем изменить это поведение, явно переопределив autoIndexCreation() метод в нашем МонгоКонфиг :
public class MongoConfig extends AbstractMongoClientConfiguration { // rest of the config goes here @Override protected boolean autoIndexCreation() { return true; } }
Давайте еще раз проверим индексы в оболочке MongoDB:
[ { "v" : 1, "key" : { "_id" : 1 }, "name" : "_id_", "ns" : "test.user" }, { "v" : 1, "key" : { "name" : 1 }, "name" : "name", "ns" : "test.user" } ]
Как видим, на этот раз у нас два индекса – один из них _id – который был создан по умолчанию из-за @Id аннотация и второй – наш имя поле.
Кроме того, если мы используем Spring Boot, мы могли бы установить spring.data.mongodb.auto-индекс- имущество для истинное .
2.2. Создание индекса программным путем
Мы также можем создать индекс программно:
mongoOps.indexOps(User.class). ensureIndex(new Index().on("name", Direction.ASC));
Сейчас мы создали индекс для полевых имя и результат будет таким же, как и в предыдущем разделе.
2.3. Составные индексы
MongoDB поддерживает сложные индексы, где единая структура индекса содержит ссылки на несколько полей.
Рассмотрим быстрый пример с использованием сложных индексов:
@QueryEntity @Document @CompoundIndexes({ @CompoundIndex(name = "email_age", def = "{'email.id' : 1, 'age': 1}") }) public class User { // }
Мы создали сложный индекс с электронной и возрастные Поля. Давайте теперь проверить фактические индексы:
{ "v" : 1, "key" : { "email.id" : 1, "age" : 1 }, "name" : "email_age", "ns" : "test.user" }
Обратите внимание, что DBRef поле не может быть помечено @Index – это поле может быть только частью составного индекса.
3. Общие аннотации
3.1. @Transient
Как и следовало ожидать, эта простая аннотация исключает, что поле сохраняется в базе данных:
public class User { @Transient private Integer yearOfBirth;
// standard getter and setter }
Давайте вставить пользователя с настройкой поля yearOfBirth :
User user = new User(); user.setName("Alex"); user.setYearOfBirth(1985); mongoTemplate.insert(user);
Теперь, если мы посмотрим состояние базы данных, мы увидим, что yearOfBirth не был спасен:
{ "_id" : ObjectId("55d8b30f758fd3c9f374499b"), "name" : "Alex", "age" : null }
Так что если мы запросим и проверим:
mongoTemplate.findOne(Query.query(Criteria.where("name").is("Alex")), User.class).getYearOfBirth()
Результат будет нулевой .
3.2. @Field
@Field указывает ключ, используемый для поля в документе JSON:
@Field("email") private EmailAddress emailAddress;
Теперь электронная почтаАдрес будут сохранены в базе данных с помощью ключа Электронная почта:
User user = new User(); user.setName("Brendan"); EmailAddress emailAddress = new EmailAddress(); emailAddress.setValue("[email protected]"); user.setEmailAddress(emailAddress); mongoTemplate.insert(user);
И состояние базы данных:
{ "_id" : ObjectId("55d076d80bad441ed114419d"), "name" : "Brendan", "age" : null, "email" : { "value" : "[email protected]" } }
3.3. @PersistenceConstructor и @Value
@PersistenceConstructor отмечает конструктора, даже защищенного пакета, чтобы быть основным конструктором, используемым логикой настойчивости. Аргументы конструктора отображаются по имени на ключевые значения в извлеченной DBОбъект .
Давайте посмотрим на этого конструктора для нашего Пользователь класс:
@PersistenceConstructor public User(String name, @Value("#root.age ?: 0") Integer age, EmailAddress emailAddress) { this.name = name; this.age = age; this.emailAddress = emailAddress; }
Обратите внимание на использование стандартного весеннего @Value аннотация здесь. С помощью этой аннотации мы можем использовать выражения весны для преобразования значения ключа, извлеченного из базы данных, прежде чем он будет использован для построения доменного объекта. Это очень мощная и очень полезная функция здесь.
В нашем примере, если возрастные не установлен, он будет установлен на 0 по умолчанию.
Давайте теперь посмотрим, как это работает:
User user = new User(); user.setName("Alex"); mongoTemplate.insert(user);
Наша база данных будет выглядеть:
{ "_id" : ObjectId("55d074ca0bad45f744a71318"), "name" : "Alex", "age" : null }
Итак, возрастные поле нулевой , но когда мы запросить документ и получить возрастные :
mongoTemplate.findOne(Query.query(Criteria.where("name").is("Alex")), User.class).getAge();
Результат будет 0.
4. Преобразователи
Давайте теперь посмотрим на другую очень полезную функцию в Весенние данные MongoDB – преобразователи, и в частности на МонгоКонвертер .
Это используется для обработки отображения всех типов Java для DBОбъекты при хранении и запросе этих объектов.
У нас есть два варианта – мы можем работать с КартаМонгоКонвертер – или ПростойМонгоКонвертер в более ранних версиях (это было deprecated в весенних данных MongoDB M3 и его функциональность была перенесена в КартаМонгоКонвертер ) .
Или мы можем написать наш собственный пользовательский преобразователь. Для этого нам необходимо будет осуществить эту Конвертер интерфейс и зарегистрировать реализацию в МонгоКонфиг.
Давайте посмотрим на быстрый пример . Как мы видели на некоторых выводах JSON, все объекты, сохраненные в базе данных, имеют поле _class который сохраняется автоматически. Если, однако, мы хотели бы пропустить это конкретное поле во время настойчивости, мы можем сделать это с помощью КартаМонгоКонвертер .
Во-первых – вот пользовательские реализации преобразователь:
@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; } }
Обратите внимание, как мы можем легко попасть в цель не _class путем конкретного удаления поля прямо здесь.
Теперь нам нужно зарегистрировать пользовательский преобразователь:
private List> converters = new ArrayList >(); @Override public MongoCustomConversions customConversions() { converters.add(new UserWriterConverter()); return new MongoCustomConversions(converters); }
Мы, конечно, можем достичь того же результата с конфигурацией XML, а также, если нам нужно:
<bean class="org.springframework.data.mongodb.core.MongoTemplate" id="mongoTemplate"> <constructor-arg name="mongo" ref="mongo"></constructor-arg> <constructor-arg ref="mongoConverter"></constructor-arg> <constructor-arg name="databaseName" value="test"></constructor-arg> </bean> <mongo:mapping-converter base-package="org.baeldung.converter" id="mongoConverter"> <mongo:custom-converters base-package="com.baeldung.converter"> </mongo:custom-converters> </mongo:mapping-converter>
Теперь, когда мы спасаем нового пользователя:
User user = new User(); user.setName("Chris"); mongoOps.insert(user);
Полученный документ в базе данных больше не содержит информацию о классе:
{ "_id" : ObjectId("55cf09790bad4394db84b853"), "name" : "Chris", "age" : null }
5. Заключение
В этом учебнике мы рассмотрели некоторые основные концепции работы с Spring Data MongoDB – индексация, общие аннотации и преобразователи.
Реализация всех этих примеров и фрагментов кода можно найти в течение на GitHub .