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

Ein Leitfaden für Abfragen in Spring Data MongoDB

1. Übersicht

Dieses Tutorial konzentriert sich auf den Aufbau verschiedener Arten von Abfragen in Spring Data MongoDB .

Wir werden uns das Abfragen von Dokumenten mit Query ansehen und Kriterien Klassen, automatisch generierte Abfragemethoden, JSON-Abfragen und QueryDSL.

Für die Einrichtung von Maven werfen Sie einen Blick auf unseren Einführungsartikel.

2. Dokumentenabfrage

Eine der gebräuchlicheren Methoden zum Abfragen von MongoDB mit Spring Data ist die Verwendung der Abfrage und Kriterien Klassen, die native Operatoren sehr genau widerspiegeln.

2.1. Ist

Dies ist einfach ein Kriterium, das Gleichheit verwendet. Mal sehen, wie es funktioniert.

Im folgenden Beispiel suchen wir nach Benutzern mit dem Namen Eric .

Sehen wir uns unsere Datenbank an:

[
    {
        "_id" : ObjectId("55c0e5e5511f0a164a581907"),
        "_class" : "org.baeldung.model.User",
        "name" : "Eric",
        "age" : 45
    },
    {
        "_id" : ObjectId("55c0e5e5511f0a164a581908"),
        "_class" : "org.baeldung.model.User",
        "name" : "Antony",
        "age" : 55
    }
}

Sehen wir uns nun den Abfragecode an:

Query query = new Query();
query.addCriteria(Criteria.where("name").is("Eric"));
List<User> users = mongoTemplate.find(query, User.class);

Wie erwartet gibt diese Logik Folgendes zurück:

{
    "_id" : ObjectId("55c0e5e5511f0a164a581907"),
    "_class" : "org.baeldung.model.User",
    "name" : "Eric",
    "age" : 45
}

2.2. Regex

Eine flexiblere und leistungsfähigere Abfrageart ist die Regex. Dadurch wird ein Kriterium mit einem $regex von MongoDB erstellt das alle Datensätze zurückgibt, die für die Regex für dieses Feld geeignet sind.

Es funktioniert ähnlich wie startingWith und endingWith Operationen.

In diesem Beispiel suchen wir nach allen Benutzern, deren Namen mit A beginnen .

Hier ist der Zustand der Datenbank:

[
    {
        "_id" : ObjectId("55c0e5e5511f0a164a581907"),
        "_class" : "org.baeldung.model.User",
        "name" : "Eric",
        "age" : 45
    },
    {
        "_id" : ObjectId("55c0e5e5511f0a164a581908"),
        "_class" : "org.baeldung.model.User",
        "name" : "Antony",
        "age" : 33
    },
    {
        "_id" : ObjectId("55c0e5e5511f0a164a581909"),
        "_class" : "org.baeldung.model.User",
        "name" : "Alice",
        "age" : 35
    }
]

Jetzt erstellen wir die Abfrage:

Query query = new Query();
query.addCriteria(Criteria.where("name").regex("^A"));
List<User> users = mongoTemplate.find(query,User.class);

Dies wird ausgeführt und gibt 2 Datensätze zurück:

[
    {
        "_id" : ObjectId("55c0e5e5511f0a164a581908"),
        "_class" : "org.baeldung.model.User",
        "name" : "Antony",
        "age" : 33
    },
    {
        "_id" : ObjectId("55c0e5e5511f0a164a581909"),
        "_class" : "org.baeldung.model.User",
        "name" : "Alice",
        "age" : 35
    }
]

Hier ist ein weiteres kurzes Beispiel, dieses Mal wird nach allen Benutzern gesucht, deren Namen mit c enden :

Query query = new Query();
query.addCriteria(Criteria.where("name").regex("c$"));
List<User> users = mongoTemplate.find(query, User.class);

Das Ergebnis wird also sein:

{
    "_id" : ObjectId("55c0e5e5511f0a164a581907"),
    "_class" : "org.baeldung.model.User",
    "name" : "Eric",
    "age" : 45
}

2.3. Lt und gt

Diese Operatoren erstellen ein Kriterium unter Verwendung von $lt (kleiner als) und $gt (größer als) Operatoren.

Nehmen wir ein kurzes Beispiel, bei dem wir nach allen Benutzern im Alter zwischen 20 und 50 suchen.

Die Datenbank ist:

[
    {
        "_id" : ObjectId("55c0e5e5511f0a164a581907"),
        "_class" : "org.baeldung.model.User",
        "name" : "Eric",
        "age" : 45
    },
    {
        "_id" : ObjectId("55c0e5e5511f0a164a581908"),
        "_class" : "org.baeldung.model.User",
        "name" : "Antony",
        "age" : 55
    }
}

Der Abfragecode:

Query query = new Query();
query.addCriteria(Criteria.where("age").lt(50).gt(20));
List<User> users = mongoTemplate.find(query,User.class);

Und die Ergebnisse für alle Nutzer mit einem Alter von über 20 und unter 50:

{
    "_id" : ObjectId("55c0e5e5511f0a164a581907"),
    "_class" : "org.baeldung.model.User",
    "name" : "Eric",
    "age" : 45
}

2.4.Sortieren

Sortieren wird verwendet, um eine Sortierreihenfolge für die Ergebnisse anzugeben.

Das folgende Beispiel gibt alle Benutzer sortiert nach Alter in aufsteigender Reihenfolge zurück.

Hier sind zunächst die vorhandenen Daten:

[
    {
        "_id" : ObjectId("55c0e5e5511f0a164a581907"),
        "_class" : "org.baeldung.model.User",
        "name" : "Eric",
        "age" : 45
    },
    {
        "_id" : ObjectId("55c0e5e5511f0a164a581908"),
        "_class" : "org.baeldung.model.User",
        "name" : "Antony",
        "age" : 33
    },
    {
        "_id" : ObjectId("55c0e5e5511f0a164a581909"),
        "_class" : "org.baeldung.model.User",
        "name" : "Alice",
        "age" : 35
    }
]

Nach dem Ausführen von sortieren :

Query query = new Query();
query.with(Sort.by(Sort.Direction.ASC, "age"));
List<User> users = mongoTemplate.find(query,User.class);

Und hier ist das Ergebnis der Abfrage, schön sortiert nach Alter :

[
    {
        "_id" : ObjectId("55c0e5e5511f0a164a581908"),
        "_class" : "org.baeldung.model.User",
        "name" : "Antony",
        "age" : 33
    },
    {
        "_id" : ObjectId("55c0e5e5511f0a164a581909"),
        "_class" : "org.baeldung.model.User",
        "name" : "Alice",
        "age" : 35
    },
    {
        "_id" : ObjectId("55c0e5e5511f0a164a581907"),
        "_class" : "org.baeldung.model.User",
        "name" : "Eric",
        "age" : 45
    }
]

2.5. Seitenfähig

Schauen wir uns ein kurzes Beispiel mit Paginierung an.

Hier ist der Zustand der Datenbank:

[
    {
        "_id" : ObjectId("55c0e5e5511f0a164a581907"),
        "_class" : "org.baeldung.model.User",
        "name" : "Eric",
        "age" : 45
    },
    {
        "_id" : ObjectId("55c0e5e5511f0a164a581908"),
        "_class" : "org.baeldung.model.User",
        "name" : "Antony",
        "age" : 33
    },
    {
        "_id" : ObjectId("55c0e5e5511f0a164a581909"),
        "_class" : "org.baeldung.model.User",
        "name" : "Alice",
        "age" : 35
    }
]

Hier ist nun die Abfragelogik, die einfach nach einer Seite der Größe 2 fragt:

final Pageable pageableRequest = PageRequest.of(0, 2);
Query query = new Query();
query.with(pageableRequest);

Und das Ergebnis, die 2 Dokumente, wie erwartet:

[
    {
        "_id" : ObjectId("55c0e5e5511f0a164a581907"),
        "_class" : "org.baeldung.model.User",
        "name" : "Eric",
        "age" : 45
    },
    {
        "_id" : ObjectId("55c0e5e5511f0a164a581908"),
        "_class" : "org.baeldung.model.User",
        "name" : "Antony",
        "age" : 33
    }
]

3. Generierte Abfragemethoden

Lassen Sie uns nun den häufigeren Abfragetyp untersuchen, den Spring Data normalerweise bereitstellt, nämlich automatisch generierte Abfragen aus Methodennamen.

Das Einzige, was wir tun müssen, um diese Art von Abfragen zu nutzen, ist, die Methode auf der Repository-Schnittstelle zu deklarieren:

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

3.1. FindByX

Wir beginnen ganz einfach, indem wir den Abfragetyp findBy untersuchen. In diesem Fall verwenden wir die Suche nach Namen:

List<User> findByName(String name);

Genau wie im vorherigen Abschnitt, 2.1, wird die Abfrage dieselben Ergebnisse haben und alle Benutzer mit dem angegebenen Namen finden:

List<User> users = userRepository.findByName("Eric");

3.2. Beginntmit und endingWith

In Abschnitt 2.2 haben wir einen regex untersucht basierte Abfrage. Starts und Ends mit sind natürlich weniger leistungsfähig, aber dennoch recht nützlich, besonders wenn wir sie nicht wirklich implementieren müssen.

Hier ist ein kurzes Beispiel dafür, wie die Vorgänge aussehen würden:

List<User> findByNameStartingWith(String regexp);
List<User> findByNameEndingWith(String regexp);

Das Beispiel für die tatsächliche Verwendung wäre natürlich sehr einfach:

List<User> users = userRepository.findByNameStartingWith("A");
List<User> users = userRepository.findByNameEndingWith("c");

Und die Ergebnisse sind genau gleich.

3.3. Zwischen

Ähnlich wie in Abschnitt 2.3 werden hier alle Benutzer mit einem Alter zwischen ageGT zurückgegeben und ageLT:

List<User> findByAgeBetween(int ageGT, int ageLT);

Der Aufruf der Methode führt dazu, dass genau die gleichen Dokumente gefunden werden:

List<User> users = userRepository.findByAgeBetween(20, 50);

3.4. Gefällt mir und OrderBy

Schauen wir uns dieses Mal ein fortgeschritteneres Beispiel an, das zwei Arten von Modifikatoren für die generierte Abfrage kombiniert.

Wir werden nach allen Benutzern suchen, deren Namen den Buchstaben A, enthalten Außerdem ordnen wir die Ergebnisse nach Alter in aufsteigender Reihenfolge:

List<User> users = userRepository.findByNameLikeOrderByAgeAsc("A");

Für die Datenbank, die wir in Abschnitt 2.4 verwendet haben, lautet das Ergebnis:

[
    {
        "_id" : ObjectId("55c0e5e5511f0a164a581908"),
        "_class" : "org.baeldung.model.User",
        "name" : "Antony",
        "age" : 33
    },
    {
        "_id" : ObjectId("55c0e5e5511f0a164a581909"),
        "_class" : "org.baeldung.model.User",
        "name" : "Alice",
        "age" : 35
    }
]

4. JSON-Abfragemethoden

Wenn wir eine Abfrage nicht mit Hilfe eines Methodennamens oder von Kriterien darstellen können, können wir etwas auf niedrigerer Ebene tun, verwenden Sie @Query Anmerkung .

Mit dieser Anmerkung können wir eine Rohabfrage als Mongo-JSON-Abfragezeichenfolge angeben.

4.1. FindBy

Fangen wir einfach an und schauen uns an, wie wir ein Finden von darstellen würden Art der Methode zuerst:

@Query("{ 'name' : ?0 }")
List<User> findUsersByName(String name);

Diese Methode sollte Benutzer nach Namen zurückgeben. Der Platzhalter?0 verweist auf den ersten Parameter der Methode.

List<User> users = userRepository.findUsersByName("Eric");

4.2. $regex

Wir können uns auch eine durch Regex gesteuerte Abfrage ansehen was natürlich das gleiche Ergebnis wie in den Abschnitten 2.2 und 3.2 liefert:

@Query("{ 'name' : { $regex: ?0 } }")
List<User> findUsersByRegexpName(String regexp);

Die Verwendung ist auch genau die gleiche:

List<User> users = userRepository.findUsersByRegexpName("^A");
List<User> users = userRepository.findUsersByRegexpName("c$");

4.3. $lt und $gt

Lassen Sie uns nun lt und gt implementieren Abfrage:

@Query("{ 'age' : { $gt: ?0, $lt: ?1 } }")
List<User> findUsersByAgeBetween(int ageGT, int ageLT);

Da die Methode nun 2 Parameter hat, referenzieren wir jeden von ihnen per Index in der Rohabfrage, ?0 und ?1:

List<User> users = userRepository.findUsersByAgeBetween(20, 50);

5. QueryDSL-Abfragen

MongoRepository bietet gute Unterstützung für das QueryDSL-Projekt, sodass wir diese nette, typsichere API auch hier nutzen können.

5.1. Die Maven-Abhängigkeiten

Stellen wir zunächst sicher, dass wir die richtigen Maven-Abhängigkeiten im pom definiert haben:

<dependency>
    <groupId>com.mysema.querydsl</groupId>
    <artifactId>querydsl-mongodb</artifactId>
    <version>4.3.1</version>
</dependency>
<dependency>
    <groupId>com.mysema.querydsl</groupId>
    <artifactId>querydsl-apt</artifactId>
    <version>4.3.1</version>
</dependency>

5.2.Q -Klassen

QueryDSL verwendete Q-Klassen zum Erstellen von Abfragen, aber da wir diese nicht wirklich von Hand erstellen wollen, müssen wir sie generieren irgendwie.

Dazu verwenden wir das apt-maven-plugin:

<plugin>    
    <groupId>com.mysema.maven</groupId>
    <artifactId>apt-maven-plugin</artifactId>
    <version>1.1.3</version>
    <executions>
        <execution>
            <goals>
                <goal>process</goal>
            </goals>
            <configuration>
                <outputDirectory>target/generated-sources/java</outputDirectory>
                <processor>
                  org.springframework.data.mongodb.repository.support.MongoAnnotationProcessor
                </processor>
            </configuration>
        </execution>
     </executions>
</plugin>

Schauen wir uns den Benutzer an -Klasse, die sich speziell auf @QueryEntity konzentriert Anmerkung:

@QueryEntity 
@Document
public class User {
 
    @Id
    private String id;
    private String name;
    private Integer age;
 
    // standard getters and setters
}

Nach dem Ausführen des Prozesses Ziel des Maven-Lebenszyklus (oder jedes andere Ziel danach) wird das apt-Plugin die neuen Klassen generieren unter target/generated-sources/java/{Ihre Paketstruktur} :

/**
 * QUser is a Querydsl query type for User
 */
@Generated("com.mysema.query.codegen.EntitySerializer")
public class QUser extends EntityPathBase<User> {

    private static final long serialVersionUID = ...;

    public static final QUser user = new QUser("user");

    public final NumberPath<Integer> age = createNumber("age", Integer.class);

    public final StringPath id = createString("id");

    public final StringPath name = createString("name");

    public QUser(String variable) {
        super(User.class, forVariable(variable));
    }

    public QUser(Path<? extends User> path) {
        super(path.getType(), path.getMetadata());
    }

    public QUser(PathMetadata<?> metadata) {
        super(User.class, metadata);
    }
}

Aufgrund dieser Klasse müssen wir unsere Abfragen nicht erstellen.

Nebenbei bemerkt, wenn wir Eclipse verwenden, wird die Einführung dieses Plugins die folgende Warnung in pom generieren:

Die MavenInstallation funktioniert einwandfrei und der QUser Klasse generiert, aber ein Plugin wird im pom hervorgehoben.

Eine schnelle Lösung besteht darin, manuell auf das JDK in eclipse.ini zu verweisen :

...
-vm
{path_to_jdk}\jdk{your_version}\bin\javaw.exe

5.3. Das neue Repository

Jetzt müssen wir tatsächlich die QueryDSL-Unterstützung in unseren Repositorys aktivieren, was durch einfaches Erweitern des QueryDslPredicateExecutor erfolgt Schnittstelle :

public interface UserRepository extends 
  MongoRepository<User, String>, QuerydslPredicateExecutor<User>

5.4. Gl.

Wenn die Unterstützung aktiviert ist, lassen Sie uns jetzt dieselben Abfragen implementieren wie die, die wir zuvor illustriert haben.

Wir beginnen mit einfacher Gleichheit:

QUser qUser = new QUser("user");
Predicate predicate = qUser.name.eq("Eric");
List<User> users = (List<User>) userRepository.findAll(predicate);

5.5. Beginntmit und EndingWith

Lassen Sie uns auf ähnliche Weise die vorherigen Abfragen implementieren und Benutzer finden, deren Namen mit A beginnen :

QUser qUser = new QUser("user");
Predicate predicate = qUser.name.startsWith("A");
List<User> users = (List<User>) userRepository.findAll(predicate);

Sowie mit c endend :

QUser qUser = new QUser("user");
Predicate predicate = qUser.name.endsWith("c");
List<User> users = (List<User>) userRepository.findAll(predicate);

Das Ergebnis ist dasselbe wie in den Abschnitten 2.2, 3.2 und 4.2.

5.6. Zwischen

Die nächste Abfrage gibt Benutzer im Alter zwischen 20 und 50 zurück, ähnlich wie in den vorherigen Abschnitten:

QUser qUser = new QUser("user");
Predicate predicate = qUser.age.between(20, 50);
List<User> users = (List<User>) userRepository.findAll(predicate);