1. Прегледа
В този урок ще разгледаме някои от основните функции на Spring Data MongoDB – индексиране, общи пояснения и конвертори.
2. Индексии
2.1. @Индексирано
Тази анотация маркира полето като индексирано в MongoDB:
@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() метод в нашия MongoConfig :
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-index-creation свойството на true .
2.2. Създайте индекс програмно
Можем също да създадем индекс програмно:
mongoOps.indexOps(User.class).
ensureIndex(new Index().on("name", Direction.ASC));
Вече създадохме индекс за полето name и резултатът ще бъде същият като в предишния раздел.
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. @Преходно
Както бихме очаквали, тази проста анотация изключва полето от запазване в базата данни:
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;
Сега emailAddress ще бъде запазен в базата данни с помощта на ключа email:
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 маркира конструктор, дори такъв, който е защитен с пакет, като основен конструктор, използван от логиката за постоянство. Аргументите на конструктора се съпоставят по име с ключовите стойности в извлечения DBObject .
Нека разгледаме този конструктор за нашия Потребител клас:
@PersistenceConstructor
public User(String name, @Value("#root.age ?: 0") Integer age, EmailAddress emailAddress) {
this.name = name;
this.age = age;
this.emailAddress = emailAddress;
}
Обърнете внимание на използването на стандартния Spring @Value анотация тук. С помощта на тази анотация можем да използваме Spring Expressions, за да трансформираме стойността на ключа, извлечена от базата данни, преди да бъде използвана за конструиране на обект на домейн. Това е много мощна и много полезна функция тук.
В нашия пример ако възраст не е зададено, ще бъде настроено на 0 по подразбиране.
Нека сега да видим как работи:
User user = new User();
user.setName("Alex");
mongoTemplate.insert(user);
Нашата база данни ще изглежда:
{
"_id" : ObjectId("55d074ca0bad45f744a71318"),
"name" : "Alex",
"age" : null
}
И така, възраст полето е null , но когато правим заявка за документа и извличаме възраст :
mongoTemplate.findOne(Query.query(Criteria.where("name").is("Alex")), User.class).getAge();
Резултатът ще бъде 0.
4. Преобразувателии
Нека сега да разгледаме друга много полезна функция в Spring Data MongoDB – конвертори, и по-специално MongoConverter .
Това се използва за обработка на съпоставянето на всички типове Java към DBObjects при съхраняване и запитване на тези обекти.
Имаме две опции – можем да работим или с MappingMongoConverter – или SimpleMongoConverter в по-ранни версии (това беше отхвърлено в Spring Data MongoDB M3 и неговата функционалност беше преместена в MappingMongoConverter ).
Или можем да напишем наш собствен персонализиран конвертор. За да направим това, ще трябва да внедрим Конвертора интерфейс и регистрирайте реализацията в MongoConfig.
Нека разгледаме бърз пример . Както видяхме в някои от изхода на JSON тук, всички обекти, записани в база данни, имат полето _class който се записва автоматично. Ако обаче искаме да пропуснем това конкретно поле по време на постоянство, можем да направим това с помощта на MappingMongoConverter .
Първо – ето персонализираната реализация на конвертора:
@Component
public class UserWriterConverter implements Converter<User, DBObject> {
@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<Converter<?,?>> converters = new ArrayList<Converter<?,?>>();
@Override
public MongoCustomConversions customConversions() {
converters.add(new UserWriterConverter());
return new MongoCustomConversions(converters);
}
Разбира се, можем да постигнем същия резултат и с XML конфигурация, ако трябва:
<bean id="mongoTemplate"
class="org.springframework.data.mongodb.core.MongoTemplate">
<constructor-arg name="mongo" ref="mongo"/>
<constructor-arg ref="mongoConverter" />
<constructor-arg name="databaseName" value="test"/>
</bean>
<mongo:mapping-converter id="mongoConverter" base-package="org.baeldung.converter">
<mongo:custom-converters base-package="com.baeldung.converter" />
</mongo:mapping-converter>
Сега, когато запазим нов потребител:
User user = new User();
user.setName("Chris");
mongoOps.insert(user);
Полученият документ в базата данни вече не съдържа информацията за класа:
{
"_id" : ObjectId("55cf09790bad4394db84b853"),
"name" : "Chris",
"age" : null
}