1. Przegląd
W tym samouczku omówimy niektóre z podstawowych funkcji Spring Data MongoDB – indeksowanie, wspólne adnotacje i konwertery.
2. Indeksy
2.1. @indeksowany
Ta adnotacja oznacza pole jako zindeksowane w MongoDB:
@QueryEntity
@Document
public class User {
@Indexed
private String name;
...
}
Teraz, gdy nazwa pole jest indeksowane – spójrzmy na indeksy w powłoce MongoDB:
db.user.getIndexes();
Oto, co otrzymujemy:
[
{
"v" : 1,
"key" : {
"_id" : 1
},
"name" : "_id_",
"ns" : "test.user"
}
]
Możemy być zaskoczeni, że nie ma śladu nazwy pole w dowolnym miejscu!
Dzieje się tak, ponieważ od Spring Data MongoDB 3.0 automatyczne tworzenie indeksów jest domyślnie wyłączone .
Możemy jednak zmienić to zachowanie, jawnie nadpisując autoIndexCreation() w naszym MongoConfig :
public class MongoConfig extends AbstractMongoClientConfiguration {
// rest of the config goes here
@Override
protected boolean autoIndexCreation() {
return true;
}
}
Sprawdźmy ponownie indeksy w powłoce MongoDB:
[
{
"v" : 1,
"key" : {
"_id" : 1
},
"name" : "_id_",
"ns" : "test.user"
},
{
"v" : 1,
"key" : {
"name" : 1
},
"name" : "name",
"ns" : "test.user"
}
]
Jak widać, tym razem mamy dwa indeksy – jednym z nich jest _id – który został utworzony domyślnie ze względu na @Id adnotacja, a druga to nasze imię pole.
Alternatywnie, jeśli używamy Spring Boot, możemy ustawić spring.data.mongodb.auto-index-creation właściwość prawda .
2.2. Utwórz indeks programowo
Możemy również utworzyć indeks programowo:
mongoOps.indexOps(User.class).
ensureIndex(new Index().on("name", Direction.ASC));
Utworzyliśmy teraz indeks dla pola nazwa a wynik będzie taki sam jak w poprzedniej sekcji.
2.3. Indeksy złożone
MongoDB obsługuje indeksy złożone, w których pojedyncza struktura indeksu zawiera odniesienia do wielu pól.
Zobaczmy szybki przykład użycia indeksów złożonych:
@QueryEntity
@Document
@CompoundIndexes({
@CompoundIndex(name = "email_age", def = "{'email.id' : 1, 'age': 1}")
})
public class User {
//
}
Stworzyliśmy indeks złożony z e-mailem i wiek pola. Sprawdźmy teraz rzeczywiste indeksy:
{
"v" : 1,
"key" : {
"email.id" : 1,
"age" : 1
},
"name" : "email_age",
"ns" : "test.user"
}
Zwróć uwagę, że DBRef pole nie może być oznaczone za pomocą @Index – to pole może być tylko częścią indeksu złożonego.
3. Popularne adnotacje
3.1. @Przejściowe
Jak można się było spodziewać, ta prosta adnotacja wyklucza utrwalenie pola w bazie danych:
public class User {
@Transient
private Integer yearOfBirth;
// standard getter and setter
}
Wstawmy użytkownika z polem ustawień yearOfBirth :
User user = new User();
user.setName("Alex");
user.setYearOfBirth(1985);
mongoTemplate.insert(user);
Teraz, jeśli spojrzymy na stan bazy danych, zobaczymy, że złożony yearOfBirth nie został zapisany:
{
"_id" : ObjectId("55d8b30f758fd3c9f374499b"),
"name" : "Alex",
"age" : null
}
Więc jeśli zapytamy i sprawdzimy:
mongoTemplate.findOne(Query.query(Criteria.where("name").is("Alex")), User.class).getYearOfBirth()
Wynik będzie null .
3.2. @Pole
@Pole wskazuje klucz, który ma być użyty dla pola w dokumencie JSON:
@Field("email")
private EmailAddress emailAddress;
Teraz adres e-mail zostaną zapisane w bazie danych za pomocą klawisza e-mail:
User user = new User();
user.setName("Brendan");
EmailAddress emailAddress = new EmailAddress();
emailAddress.setValue("[email protected]");
user.setEmailAddress(emailAddress);
mongoTemplate.insert(user);
I stan bazy danych:
{
"_id" : ObjectId("55d076d80bad441ed114419d"),
"name" : "Brendan",
"age" : null,
"email" : {
"value" : "[email protected]"
}
}
3.3. @PersistenceConstructor i @Wartość
@PersistenceConstructor oznacza konstruktora, nawet takiego, który jest chroniony przez pakiet, jako głównego konstruktora używanego przez logikę trwałości. Argumenty konstruktora są mapowane według nazwy na wartości klucza w pobranym DBObject .
Spójrzmy na ten konstruktor dla naszego użytkownika klasa:
@PersistenceConstructor
public User(String name, @Value("#root.age ?: 0") Integer age, EmailAddress emailAddress) {
this.name = name;
this.age = age;
this.emailAddress = emailAddress;
}
Zwróć uwagę na użycie standardowego Springa @Value adnotacja tutaj. To za pomocą tej adnotacji możemy użyć Spring Expressions do przekształcenia wartości klucza pobranej z bazy danych, zanim zostanie ona użyta do skonstruowania obiektu domeny. To bardzo potężna i bardzo przydatna funkcja.
W naszym przykładzie, jeśli wiek nie jest ustawiona, zostanie ustawiona na 0 domyślnie.
Zobaczmy teraz, jak to działa:
User user = new User();
user.setName("Alex");
mongoTemplate.insert(user);
Nasza baza danych będzie wyglądać:
{
"_id" : ObjectId("55d074ca0bad45f744a71318"),
"name" : "Alex",
"age" : null
}
A więc wiek pole jest puste , ale gdy wysyłamy zapytanie do dokumentu i pobieramy wiek :
mongoTemplate.findOne(Query.query(Criteria.where("name").is("Alex")), User.class).getAge();
Wynik będzie równy 0.
4. Konwertery
Przyjrzyjmy się teraz innej bardzo przydatnej funkcji w Spring Data MongoDB — konwerterom, a konkretnie MongoConverter .
Służy do obsługi mapowania wszystkich typów Javy na DBObjects podczas przechowywania i odpytywania tych obiektów.
Mamy dwie opcje – możemy albo pracować z MappingMongoConverter – lub SimpleMongoConverter we wcześniejszych wersjach (zostało to przestarzałe w Spring Data MongoDB M3, a jego funkcjonalność została przeniesiona do MappingMongoConverter ).
Lub możemy napisać własny niestandardowy konwerter. Aby to zrobić, musielibyśmy zaimplementować Konwerter interfejs i zarejestruj implementację w MongoConfig.
Spójrzmy na krótki przykład . Jak widzieliśmy w niektórych danych wyjściowych JSON tutaj, wszystkie obiekty zapisane w bazie danych mają pole _class który jest zapisywany automatycznie. Jeśli jednak chcielibyśmy pominąć to konkretne pole podczas trwałości, możemy to zrobić za pomocą MappingMongoConverter .
Po pierwsze – oto implementacja niestandardowego konwertera:
@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;
}
}
Zwróć uwagę, jak możemy łatwo osiągnąć cel, jakim jest nieutrzymywanie się _class usuwając to pole bezpośrednio tutaj.
Teraz musimy zarejestrować niestandardowy konwerter:
private List<Converter<?,?>> converters = new ArrayList<Converter<?,?>>();
@Override
public MongoCustomConversions customConversions() {
converters.add(new UserWriterConverter());
return new MongoCustomConversions(converters);
}
Możemy oczywiście osiągnąć ten sam wynik również z konfiguracją XML, jeśli zajdzie taka potrzeba:
<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>
Teraz, gdy zapisujemy nowego użytkownika:
User user = new User();
user.setName("Chris");
mongoOps.insert(user);
Wynikowy dokument w bazie danych nie zawiera już informacji o klasie:
{
"_id" : ObjectId("55cf09790bad4394db84b853"),
"name" : "Chris",
"age" : null
}