MongoDB
 sql >> Datenbank >  >> NoSQL >> MongoDB

Spring Data MongoDB – Indizes, Anmerkungen und Konverter

1. Übersicht

In diesem Tutorial werden wir einige der Kernfunktionen von Spring Data MongoDB untersuchen – Indizierung, allgemeine Anmerkungen und Konverter.

2. Indizes

2.1. @Indexiert

Diese Anmerkung markiert das Feld als indexiert in MongoDB:

@QueryEntity
@Document
public class User {
    @Indexed
    private String name;
    
    ... 
}

Nun, da der Name Das Feld ist indiziert – schauen wir uns die Indizes in der MongoDB-Shell an:

db.user.getIndexes();

Folgendes erhalten wir:

[
    {
        "v" : 1,
        "key" : {
             "_id" : 1
         },
        "name" : "_id_",
        "ns" : "test.user"
    }
]

Wir werden vielleicht überrascht sein, dass der Name nicht zu sehen ist Feld überall!

Dies liegt daran, dass ab Spring Data MongoDB 3.0 die automatische Indexerstellung standardmäßig deaktiviert ist .

Wir können dieses Verhalten jedoch ändern, indem wir autoIndexCreation() explizit überschreiben Methode in unserer MongoConfig :

public class MongoConfig extends AbstractMongoClientConfiguration {

    // rest of the config goes here

    @Override
    protected boolean autoIndexCreation() {
        return true;
    }
}

Sehen wir uns noch einmal die Indizes in der MongoDB-Shell an:

[
    {
        "v" : 1,
        "key" : {
             "_id" : 1
         },
        "name" : "_id_",
        "ns" : "test.user"
    },
    {
         "v" : 1,
         "key" : {
             "name" : 1
          },
          "name" : "name",
          "ns" : "test.user"
     }
]

Wie wir sehen können, haben wir diesmal zwei Indizes – einer davon ist _id – die standardmäßig aufgrund der @Id erstellt wurde Anmerkung und der zweite ist unser Name Feld.

Alternativ, wenn wir Spring Boot verwenden, könnten wir die spring.data.mongodb.auto-index-creation einstellen Eigenschaft auf true .

2.2. Erstellen Sie programmgesteuert einen Index

Wir können einen Index auch programmgesteuert erstellen:

mongoOps.indexOps(User.class).
  ensureIndex(new Index().on("name", Direction.ASC));

Wir haben jetzt einen Index für das Feld name erstellt und das Ergebnis ist dasselbe wie im vorherigen Abschnitt.

2.3. Zusammengesetzte Indizes

MongoDB unterstützt zusammengesetzte Indizes, bei denen eine einzelne Indexstruktur Verweise auf mehrere Felder enthält.

Sehen wir uns ein kurzes Beispiel mit zusammengesetzten Indizes an:

@QueryEntity
@Document
@CompoundIndexes({
    @CompoundIndex(name = "email_age", def = "{'email.id' : 1, 'age': 1}")
})
public class User {
    //
}

Wir haben einen zusammengesetzten Index mit der E-Mail erstellt und Alter Felder. Sehen wir uns nun die eigentlichen Indizes an:

{
    "v" : 1,
    "key" : {
        "email.id" : 1,
        "age" : 1
    },
    "name" : "email_age",
    "ns" : "test.user"
}

Beachten Sie, dass ein DBRef Feld kann nicht mit @Index markiert werden – dieses Feld kann nur Teil eines zusammengesetzten Indexes sein.

3. Allgemeine Anmerkungen

3.1. @Transient

Wie zu erwarten, schließt diese einfache Anmerkung aus, dass das Feld in der Datenbank gespeichert wird:

public class User {
    
    @Transient
    private Integer yearOfBirth;
    // standard getter and setter

}

Lassen Sie uns den Benutzer mit dem Einstellungsfeld yearOfBirth einfügen :

User user = new User();
user.setName("Alex");
user.setYearOfBirth(1985);
mongoTemplate.insert(user);

Wenn wir uns nun den Status der Datenbank ansehen, sehen wir, dass das Feld yearOfBirth wurde nicht gespeichert:

{
    "_id" : ObjectId("55d8b30f758fd3c9f374499b"),
    "name" : "Alex",
    "age" : null
}

Wenn wir also abfragen und prüfen:

mongoTemplate.findOne(Query.query(Criteria.where("name").is("Alex")), User.class).getYearOfBirth()

Das Ergebnis ist null .

3.2. @Feld

@Feld gibt den Schlüssel an, der für das Feld im JSON-Dokument verwendet werden soll:

@Field("email")
private EmailAddress emailAddress;

Jetzt E-Mail-Adresse werden mit dem Schlüssel email: in der Datenbank gespeichert

User user = new User();
user.setName("Brendan");
EmailAddress emailAddress = new EmailAddress();
emailAddress.setValue("[email protected]");
user.setEmailAddress(emailAddress);
mongoTemplate.insert(user);

Und der Zustand der Datenbank:

{
    "_id" : ObjectId("55d076d80bad441ed114419d"),
    "name" : "Brendan",
    "age" : null,
    "email" : {
        "value" : "[email protected]"
    }
}

3.3. @PersistenceConstructor und @Wert

@PersistenceConstructor markiert einen Konstruktor, selbst einen paketgeschützten, als primären Konstruktor, der von der Persistenzlogik verwendet wird. Die Konstruktorargumente werden nach Namen den Schlüsselwerten im abgerufenen DBObject zugeordnet .

Sehen wir uns diesen Konstruktor für unseren Benutzer an Klasse:

@PersistenceConstructor
public User(String name, @Value("#root.age ?: 0") Integer age, EmailAddress emailAddress) {
    this.name =  name;
    this.age = age;
    this.emailAddress =  emailAddress;
}

Beachten Sie die Verwendung des Spring-Standards @Value Anmerkung hier. Mit Hilfe dieser Anmerkung können wir die Spring-Ausdrücke verwenden, um den Wert eines Schlüssels zu transformieren, der aus der Datenbank abgerufen wird, bevor er zum Erstellen eines Domänenobjekts verwendet wird. Das ist hier eine sehr mächtige und äußerst nützliche Funktion.

In unserem Beispiel wenn Alter nicht gesetzt ist, wird es auf 0 gesetzt standardmäßig.

Sehen wir uns nun an, wie es funktioniert:

User user = new User();
user.setName("Alex");
mongoTemplate.insert(user);

Unsere Datenbank sieht so aus:

{
    "_id" : ObjectId("55d074ca0bad45f744a71318"),
    "name" : "Alex",
    "age" : null
}

Also das Alter Feld ist null , aber wenn wir das Dokument abfragen und age abrufen :

mongoTemplate.findOne(Query.query(Criteria.where("name").is("Alex")), User.class).getAge();

Das Ergebnis ist 0.

4. Konverter

Werfen wir nun einen Blick auf eine weitere sehr nützliche Funktion in Spring Data MongoDB – Konverter und insbesondere auf den MongoConverter .

Dies wird verwendet, um die Zuordnung aller Java-Typen zu DBObjects zu handhaben beim Speichern und Abfragen dieser Objekte.

Wir haben zwei Möglichkeiten – wir können entweder mit MappingMongoConverter – arbeiten oder SimpleMongoConverter in früheren Versionen (dies war in Spring Data MongoDB M3 veraltet und seine Funktionalität wurde in MappingMongoConverter verschoben ).

Oder wir können unseren eigenen benutzerdefinierten Konverter schreiben. Dazu müssten wir den Converter implementieren Schnittstelle und registrieren Sie die Implementierung in MongoConfig.

Schauen wir uns ein kurzes Beispiel an . Wie wir in einigen der JSON-Ausgaben hier gesehen haben, haben alle in einer Datenbank gespeicherten Objekte das Feld _class die automatisch gespeichert wird. Wenn wir jedoch dieses bestimmte Feld während der Persistenz überspringen möchten, können wir dies mit einem MappingMongoConverter tun .

Zuerst – hier ist die Implementierung des benutzerdefinierten Konverters:

@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;
    }
}

Beachten Sie, wie leicht wir das Ziel erreichen können, _class nicht zu persistieren indem Sie das Feld gezielt direkt hier entfernen.

Jetzt müssen wir den benutzerdefinierten Konverter registrieren:

private List<Converter<?,?>> converters = new ArrayList<Converter<?,?>>();

@Override
public MongoCustomConversions customConversions() {
    converters.add(new UserWriterConverter());
    return new MongoCustomConversions(converters);
}

Dasselbe Ergebnis können wir natürlich auch mit der XML-Konfiguration erzielen, wenn es nötig ist:

<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>

Wenn wir jetzt einen neuen Benutzer speichern:

User user = new User();
user.setName("Chris");
mongoOps.insert(user);

Das resultierende Dokument in der Datenbank enthält nicht mehr die Klasseninformationen:

{
    "_id" : ObjectId("55cf09790bad4394db84b853"),
    "name" : "Chris",
    "age" : null
}