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

Einführung in Spring Data MongoDB

1. Übersicht

Dieser Artikel ist eine schnelle und praktische Einführung in Spring Data MongoDB.

Wir werden die Grundlagen mit dem MongoTemplate besprechen sowie MongoRepository , mit praktischen Beispielen zur Veranschaulichung jeder Operation.


Weiterführende Literatur:

Georäumliche Unterstützung in MongoDB

Sehen Sie sich an, wie Sie Geodaten mit MongoDB speichern, indizieren und durchsuchen. Lesen Sie mehr →

Spring Boot-Integrationstests mit eingebettetem MongoDB

Erfahren Sie, wie Sie die eingebettete MongoDB-Lösung von Flapdoodle zusammen mit Spring Boot verwenden, um MongoDB-Integrationstests reibungslos auszuführen. Lesen Sie mehr →

2. MongoTemplate und MongoRepository

Das MongoTemplate folgt dem Standardvorlagenmuster in Spring und stellt eine sofort einsatzbereite, grundlegende API für die zugrunde liegende Persistenz-Engine bereit.

Das Repository folgt dem Spring Data-zentrierten Ansatz und verfügt über flexiblere und komplexere API-Operationen, basierend auf den bekannten Zugriffsmustern in allen Spring Data-Projekten.

Für beide müssen wir zunächst die Abhängigkeit definieren – zum Beispiel in der pom.xml , mit Maven:

<dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-mongodb</artifactId>
    <version>3.0.3.RELEASE</version>
</dependency>

Um zu überprüfen, ob eine neue Version der Bibliothek veröffentlicht wurde, verfolgen Sie die Veröffentlichungen hier.

3. Konfiguration für MongoTemplate

3.1. XML-Konfiguration

Beginnen wir mit der einfachen XML-Konfiguration für das Mongo-Template:

<mongo:mongo-client id="mongoClient" host="localhost" />
<mongo:db-factory id="mongoDbFactory" dbname="test" mongo-client-ref="mongoClient" />

Zuerst müssen wir das Factory-Bean definieren, das für die Erstellung von Mongo-Instanzen verantwortlich ist.

Als nächstes müssen wir die Template-Bean tatsächlich definieren (und konfigurieren):

<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate"> 
    <constructor-arg ref="mongoDbFactory"/> 
</bean>

Und schließlich müssen wir einen Postprozessor definieren, um alle MongoExceptions zu übersetzen in @Repository geworfen kommentierte Klassen:

<bean class=
  "org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>

3.2. Java-Konfiguration

Lassen Sie uns nun eine ähnliche Konfiguration mit Java Config erstellen, indem wir die Basisklasse für die MongoDB-Konfiguration AbstractMongoConfiguration erweitern :

@Configuration
public class MongoConfig extends AbstractMongoClientConfiguration {
 
    @Override
    protected String getDatabaseName() {
        return "test";
    }
 
    @Override
    public MongoClient mongoClient() {
        ConnectionString connectionString = new ConnectionString("mongodb://localhost:27017/test");
        MongoClientSettings mongoClientSettings = MongoClientSettings.builder()
            .applyConnectionString(connectionString)
            .build();
        
        return MongoClients.create(mongoClientSettings);
    }
 
    @Override
    public Collection getMappingBasePackages() {
        return Collections.singleton("com.baeldung");
    }
}

Beachten Sie, dass wir MongoTemplate nicht definieren mussten Bean in der vorherigen Konfiguration, da sie bereits in AbstractMongoClientConfiguration definiert ist .

Wir können unsere Konfiguration auch von Grund auf neu verwenden, ohne AbstractMongoClientConfiguration zu erweitern :

@Configuration
public class SimpleMongoConfig {
 
    @Bean
    public MongoClient mongo() {
        ConnectionString connectionString = new ConnectionString("mongodb://localhost:27017/test");
        MongoClientSettings mongoClientSettings = MongoClientSettings.builder()
          .applyConnectionString(connectionString)
          .build();
        
        return MongoClients.create(mongoClientSettings);
    }

    @Bean
    public MongoTemplate mongoTemplate() throws Exception {
        return new MongoTemplate(mongo(), "test");
    }
}

4. Konfiguration für MongoRepository

4.1. XML-Konfiguration

Um benutzerdefinierte Repositorys zu verwenden (Erweitern des MongoRepository ), müssen wir die Konfiguration aus Abschnitt 3.1 fortsetzen. und richten Sie die Repositories ein:

<mongo:repositories 
  base-package="com.baeldung.repository" mongo-template-ref="mongoTemplate"/>

4.2. Java-Konfiguration

In ähnlicher Weise bauen wir auf der Konfiguration auf, die wir bereits in Abschnitt 3.2 erstellt haben. und fügen Sie dem Mix eine neue Anmerkung hinzu:

@EnableMongoRepositories(basePackages = "com.baeldung.repository")

4.3. Erstellen Sie das Repository

Nach der Konfiguration müssen wir ein Repository erstellen – das bestehende MongoRepository erweitern Schnittstelle:

public interface UserRepository extends MongoRepository<User, String> {
    // 
}

Jetzt können wir dieses UserRepository automatisch verbinden und verwenden Sie Vorgänge aus MongoRepository oder benutzerdefinierte Operationen hinzufügen.

5. Verwenden von MongoTemplate

5.1. Einfügen

Beginnen wir mit der Einfügeoperation sowie einer leeren Datenbank:

{
}

Wenn wir jetzt einen neuen Benutzer einfügen:

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

die Datenbank sieht so aus:

{
    "_id" : ObjectId("55b4fda5830b550a8c2ca25a"),
    "_class" : "com.baeldung.model.User",
    "name" : "Jon"
}

5.2. Speichern – Einfügen

Die speichern Die Operation hat eine Speichern-oder-Aktualisieren-Semantik:Wenn eine ID vorhanden ist, führt sie eine Aktualisierung durch, und wenn nicht, führt sie eine Einfügung durch.

Schauen wir uns die erste Semantik an – die Einfügung.

Hier ist der Ausgangszustand der Datenbank:

{
}

Wenn wir jetzt speichern ein neuer Benutzer:

User user = new User();
user.setName("Albert"); 
mongoTemplate.save(user, "user");

Die Entität wird in die Datenbank eingefügt:

{
    "_id" : ObjectId("55b52bb7830b8c9b544b6ad5"),
    "_class" : "com.baeldung.model.User",
    "name" : "Albert"
}

Als Nächstes sehen wir uns dieselbe Operation an – save — mit Update-Semantik.

5.3. Speichern – Aktualisieren

Sehen wir uns nun speichern an mit Aktualisierungssemantik, die auf einer bestehenden Entität operiert:

{
    "_id" : ObjectId("55b52bb7830b8c9b544b6ad5"),
    "_class" : "com.baeldung.model.User",
    "name" : "Jack"
}

Wenn wir speichern den bestehenden Benutzer, wir werden ihn aktualisieren:

user = mongoTemplate.findOne(
  Query.query(Criteria.where("name").is("Jack")), User.class);
user.setName("Jim");
mongoTemplate.save(user, "user");

Die Datenbank sieht folgendermaßen aus:

{
    "_id" : ObjectId("55b52bb7830b8c9b544b6ad5"),
    "_class" : "com.baeldung.model.User",
    "name" : "Jim"
}

Wir können das in diesem speziellen Beispiel sehen, speichern verwendet die Semantik von update weil wir ein Objekt mit gegebener _id verwenden .

5.4. Zuerst aktualisieren

updateFirst aktualisiert das allererste Dokument, das der Abfrage entspricht.

Beginnen wir mit dem Anfangszustand der Datenbank:

[
    {
        "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
        "_class" : "com.baeldung.model.User",
        "name" : "Alex"
    },
    {
        "_id" : ObjectId("55b5ffa5511fee0e45ed614c"),
        "_class" : "com.baeldung.model.User",
        "name" : "Alex"
    }
]

Wenn wir jetzt das updateFirst ausführen :

Query query = new Query();
query.addCriteria(Criteria.where("name").is("Alex"));
Update update = new Update();
update.set("name", "James");
mongoTemplate.updateFirst(query, update, User.class);

nur der erste Eintrag wird aktualisiert:

[
    {
        "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
        "_class" : "com.baeldung.model.User",
        "name" : "James"
    },
    {
        "_id" : ObjectId("55b5ffa5511fee0e45ed614c"),
        "_class" : "com.baeldung.model.User",
        "name" : "Alex"
    }
]

5.5. UpdateMulti

UpdateMulti aktualisiert alle Dokumente, die der angegebenen Abfrage entsprechen.

Hier ist zunächst der Status der Datenbank vor dem updateMulti :

[
    {
        "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
        "_class" : "com.baeldung.model.User",
        "name" : "Eugen"
    },
    {
        "_id" : ObjectId("55b5ffa5511fee0e45ed614c"),
        "_class" : "com.baeldung.model.User",
        "name" : "Eugen"
    }
]

Lassen Sie uns nun updateMulti ausführen Betrieb:

Query query = new Query();
query.addCriteria(Criteria.where("name").is("Eugen"));
Update update = new Update();
update.set("name", "Victor");
mongoTemplate.updateMulti(query, update, User.class);

Beide bestehenden Objekte werden in der Datenbank aktualisiert:

[
    {
        "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
        "_class" : "com.baeldung.model.User",
        "name" : "Victor"
    },
    {
        "_id" : ObjectId("55b5ffa5511fee0e45ed614c"),
        "_class" : "com.baeldung.model.User",
        "name" : "Victor"
    }
]

5.6. FindenUndÄndern

Diese Operation funktioniert wie updateMulti , aber es gibt das Objekt zurück, bevor es geändert wurde.

Erstens ist dies der Zustand der Datenbank vor dem Aufruf von findAndModify :

{
    "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
    "_class" : "com.baeldung.model.User",
    "name" : "Markus"
}

Schauen wir uns den eigentlichen Operationscode an:

Query query = new Query();
query.addCriteria(Criteria.where("name").is("Markus"));
Update update = new Update();
update.set("name", "Nick");
User user = mongoTemplate.findAndModify(query, update, User.class);

Das zurückgegebene Benutzerobjekt hat dieselben Werte wie der Anfangszustand in der Datenbank.

Dies ist jedoch der neue Stand in der Datenbank:

{
    "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
    "_class" : "com.baeldung.model.User",
    "name" : "Nick"
}

5.7. Upsert

Der Upsert arbeitet an der find and modify else create Semantik :Wenn das Dokument übereinstimmt, aktualisieren Sie es oder erstellen Sie ein neues Dokument, indem Sie die Abfrage und das Aktualisierungsobjekt kombinieren.

Beginnen wir mit dem Anfangszustand der Datenbank:

{
    "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
    "_class" : "com.baeldung.model.User",
    "name" : "Markus"
}

Lassen Sie uns nun den Upsert ausführen :

Query query = new Query();
query.addCriteria(Criteria.where("name").is("Markus"));
Update update = new Update();
update.set("name", "Nick");
mongoTemplate.upsert(query, update, User.class);

Hier ist der Zustand der Datenbank nach der Operation:

{
    "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
    "_class" : "com.baeldung.model.User",
    "name" : "Nick"
}

5.8. Entfernen

Wir sehen uns den Zustand der Datenbank an, bevor wir remove aufrufen :

{
    "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
    "_class" : "com.baeldung.model.User",
    "name" : "Benn"
}

Lassen Sie uns nun remove ausführen :

mongoTemplate.remove(user, "user");

Das Ergebnis ist wie erwartet:

{
}

6. Verwenden von MongoRepository

6.1. Einfügen

Zuerst sehen wir den Status der Datenbank, bevor wir insert ausführen :

{
}

Jetzt fügen wir einen neuen Benutzer ein:

User user = new User();
user.setName("Jon");
userRepository.insert(user);

Und hier ist der Endzustand der Datenbank:

{
    "_id" : ObjectId("55b4fda5830b550a8c2ca25a"),
    "_class" : "com.baeldung.model.User",
    "name" : "Jon"
}

Beachten Sie, dass die Operation genauso funktioniert wie insert im MongoTemplate API.

6.2. Speichern Einfügen

Ebenso speichern funktioniert genauso wie das speichern Vorgang im MongoTemplate API.

Sehen wir uns zunächst die Insert-Semantik an der Operation.

Hier ist der Ausgangszustand der Datenbank:

{
}

Nun führen wir das Speichern aus Betrieb:

User user = new User();
user.setName("Aaron");
userRepository.save(user);

Dies führt dazu, dass der Benutzer zur Datenbank hinzugefügt wird:

{
    "_id" : ObjectId("55b52bb7830b8c9b544b6ad5"),
    "_class" : "com.baeldung.model.User",
    "name" : "Aaron"
}

Beachten Sie noch einmal, wie speichern funktioniert mit insert Semantik, weil wir ein neues Objekt einfügen.

6.3. Speichern Aktualisieren

Betrachten wir nun dieselbe Operation, jedoch mit Aktualisierungssemantik.

Hier ist zunächst der Status der Datenbank, bevor das neue Speichern ausgeführt wird :

{
    "_id" : ObjectId("55b52bb7830b8c9b544b6ad5"),
    "_class" : "com.baeldung.model.User",
    "name" : "Jack"81*6
}

Nun führen wir die Operation aus:

user = mongoTemplate.findOne(
  Query.query(Criteria.where("name").is("Jack")), User.class);
user.setName("Jim");
userRepository.save(user);

Schließlich ist hier der Zustand der Datenbank:

{
    "_id" : ObjectId("55b52bb7830b8c9b544b6ad5"),
    "_class" : "com.baeldung.model.User",
    "name" : "Jim"
}

Beachten Sie noch einmal, wie speichern funktioniert mit update Semantik, da wir ein vorhandenes Objekt verwenden.

6.4. Löschen

Hier ist der Zustand der Datenbank vor dem Aufruf von delete :

{
    "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
    "_class" : "com.baeldung.model.User",
    "name" : "Benn"
}

Lassen Sie uns delete ausführen :

userRepository.delete(user);

Und hier ist unser Ergebnis:

{
}

6.5. FindOne

Als nächstes ist dies der Zustand der Datenbank, wenn findOne heißt:

{
    "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
    "_class" : "com.baeldung.model.User",
    "name" : "Chris"
}

Lassen Sie uns nun findOne ausführen :

userRepository.findOne(user.getId())

Und das Ergebnis gibt die vorhandenen Daten zurück:

{
    "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
    "_class" : "com.baeldung.model.User",
    "name" : "Chris"
}

6.6. Existiert

Der Zustand der Datenbank vor dem Aufruf von exists :

{
    "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
    "_class" : "com.baeldung.model.User",
    "name" : "Harris"
}

Lassen Sie uns nun exists ausführen , was natürlich true zurückgibt :

boolean isExists = userRepository.exists(user.getId());

6.7. FindAll MitSortieren

Der Zustand der Datenbank vor dem Aufruf von findAll :

[
    {
        "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
        "_class" : "com.baeldung.model.User",
        "name" : "Brendan"
    },
    {
        "_id" : ObjectId("67b5ffa5511fee0e45ed614b"),
        "_class" : "com.baeldung.model.User",
        "name" : "Adam"
    }
]

Lassen Sie uns nun findAll ausführen mitSortieren :

List<User> users = userRepository.findAll(Sort.by(Sort.Direction.ASC, "name"));

Das Ergebnis wird aufsteigend nach Namen sortiert :

[
    {
        "_id" : ObjectId("67b5ffa5511fee0e45ed614b"),
        "_class" : "com.baeldung.model.User",
        "name" : "Adam"
    },
    {
        "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
        "_class" : "com.baeldung.model.User",
        "name" : "Brendan"
    }
]

6.8. FindAll Mit Pageable

Der Zustand der Datenbank vor dem Aufruf von findAll :

[
    {
        "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
        "_class" : "com.baeldung.model.User",
        "name" : "Brendan"
    },
    {
        "_id" : ObjectId("67b5ffa5511fee0e45ed614b"),
        "_class" : "com.baeldung.model.User",
        "name" : "Adam"
    }
]

Lassen Sie uns nun findAll ausführen mit einer Paginierungsanfrage:

Pageable pageableRequest = PageRequest.of(0, 1);
Page<User> page = userRepository.findAll(pageableRequest);
List<User> users = pages.getContent();

Die resultierenden Benutzer Liste wird nur ein Benutzer sein:

{
    "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
    "_class" : "com.baeldung.model.User",
    "name" : "Brendan"
}

7. Anmerkungen

Lassen Sie uns abschließend auch die einfachen Anmerkungen durchgehen, die Spring Data verwendet, um diese API-Operationen zu steuern.

Die Feldebene @Id Annotation kann jeden Typ schmücken, einschließlich long und Zeichenfolge :

@Id
private String id;

Wenn der Wert der @Id Feld ist nicht null, es wird unverändert in der Datenbank gespeichert; Andernfalls geht der Konverter davon aus, dass wir eine ObjectId speichern möchten in der Datenbank (entweder ObjectId , Zeichenfolge oder BigInteger Arbeit).

Als nächstes sehen wir uns @Document an :

@Document
public class User {
    //
}

Diese Anmerkung markiert eine Klasse einfach als Domänenobjekt die in der Datenbank gespeichert werden muss, zusammen mit der Möglichkeit, den Namen der zu verwendenden Sammlung auszuwählen.