Spring Data MongoDB - Indizes, Anmerkungen und Konverter

Spring Data MongoDB - Indizes, Anmerkungen und Konverter

1. Überblick

In diesem Tutorial werden einige der Hauptfunktionen von Spring Data MongoDB vorgestellt - Indizierung, allgemeine Anmerkungen und Konverter.

2. Indizes

2.1. @Indexed

Diese Anmerkungmarks the field as indexed in MongoDB:

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

    ...
}

Nachdem das Feldnameindiziert ist, werfen wir einen Blick auf die Indizes in MongoDB:

db.user.getIndexes();

Folgendes haben wir auf Datenbankebene:

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

Wie Sie sehen können, haben wir zwei Indizes - einer davon ist_id -, die aufgrund der Annotation@Id undthe second one is our name field. standardmäßig erstellt wurden

2.2. Programmgesteuert einen Index erstellen

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 Feldname erstellt. Das Ergebnis ist das gleiche wie im vorherigen Abschnitt.

2.3. Zusammengesetzte Indizes

MongoDB unterstützt zusammengesetzte Indizes, wobei 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 den Feldernemail undage erstellt. Schauen wir uns nun die tatsächlichen Indizes an:

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

Beachten Sie, dass einDBRef-Feld nicht mit@Index markiert werden kann - dieses Feld kann nur Teil eines zusammengesetzten Index sein.

3. Allgemeine Anmerkungen

3.1 @Transient

Wie zu erwarten, wird durch diese einfache Annotation ausgeschlossen, dass das Feld in der Datenbank beibehalten wird:

public class User {

    @Transient
    private Integer yearOfBirth;
    // standard getter and setter

}

Fügen Sie den Benutzer mit dem EinstellungsfeldyearOfBirth ein:

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 die abgelegtenyearOfBirth nicht gespeichert wurden:

{
    "_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 istnull.

3.2. @Field

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

@Field("email")
private EmailAddress emailAddress;

Nun werdenemailAddress in der Datenbank gespeichert, wobei der Schlüsselemail: verwendet wird.

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

Und der Status der Datenbank:

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

3.3. @PersistenceConstructor und@Value

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

Schauen wir uns diesen Konstruktor für unsereUser-Klasse an:

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

Beachten Sie hier die Verwendung der Standardanmerkung Spring@Value. Mithilfe dieser Anmerkung können wir die Spring-Ausdrücke verwenden, um den aus der Datenbank abgerufenen Schlüsselwert zu transformieren, bevor er zum Erstellen eines Domänenobjekts verwendet wird. Dies ist eine sehr leistungsstarke und äußerst nützliche Funktion.

Wenn in unserem Beispielage nicht festgelegt ist, wird es standardmäßig auf0 festgelegt.

Mal sehen, wie es funktioniert:

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

Unsere Datenbank wird aussehen:

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

Das Feldage ist alsonull, aber wenn wir das Dokument abfragen undage abrufen:

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

Das Ergebnis ist 0.

4. Konverter

Schauen wir uns nun eine weitere sehr nützliche Funktion in Spring Data MongoDB an - Konverter, insbesondere dieMongoConverter.

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

Wir haben zwei Möglichkeiten: Wir können entweder mitMappingMongoConverter – oderSimpleMongoConverter in früheren Versionen arbeiten (dies war in Spring Data MongoDB M3 veraltet und seine Funktionalität wurde inMappingMongoConverter).verschoben. s

Oder wir können unseren eigenen benutzerdefinierten Konverter schreiben. Dazu müssten wir dieConverter-Schnittstelle implementieren und die Implementierung inMongoConfig. registrieren

Schauen wir unsa quick example an. Wie Sie in einigen JSON-Ausgaben hier gesehen haben, haben alle in einer Datenbank gespeicherten Objekte das Feld_class, das automatisch gespeichert wird. Wenn wir dieses bestimmte Feld jedoch während der Persistenz überspringen möchten, können wir dies mitMappingMongoConverter tun.

Erstens - hier ist die Implementierung des benutzerdefinierten Konverters:

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

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

Jetzt müssen wir den benutzerdefinierten Konverter registrieren:

private List> converters = new ArrayList>();

@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 wir:


    
    
    



    

Jetzt, wenn wir einen neuen Benutzer speichern:

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

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

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

5. Fazit

In diesem Tutorial haben wir einige Kernkonzepte der Arbeit mit Spring Data MongoDB behandelt - Indizierung, allgemeine Anmerkungen und Konverter.

Die Implementierung all dieser Beispiele und Codefragmentecan be found inmy github project - dies ist ein Eclipse-basiertes Projekt, daher sollte es einfach zu importieren und auszuführen sein, wie es ist.