MongoDB
 sql >> Baza danych >  >> NoSQL >> MongoDB

Spring Data MongoDB – indeksy, adnotacje i konwertery

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
}

  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Jaka jest różnica między id i _id w manguście?

  2. Wykorzystanie indeksu złożonego MongoDB

  3. Jak znaleźć przecięcie zestawów między dokumentami w jednej kolekcji w MongoDB?

  4. Rozwiązywanie problemów z klastrem z fragmentami MongoDB

  5. MongoDB:Przekroczono limit czasu po wybraniu serwera przez 30000 ms za pomocą CompositeServerSelector