Ein Leitfaden für Abfragen in Spring Data MongoDB

Ein Leitfaden für Abfragen in Spring Data MongoDB

1. Überblick

Dieser Artikel konzentriert sich auf den Aufbau verschiedenertypes of queries in Spring Data MongoDB.

Wir werden Dokumente mit den KlassenQuery undCriteria, automatisch generierten Abfragemethoden, JSON-Abfragen und QueryDSL abfragen.

Schauen Sie sich für das Maven-Setup unsereintroductory articlean.

2. Dokumentenabfrage

Eine der gebräuchlichsten Methoden zum Abfragen von MongoDB mit Spring Data ist die Verwendung der KlassenQuery undCriteria, die native Operatoren sehr genau widerspiegeln.

2.1. Is

Dies ist einfach ein Kriterium für die Verwendung von Gleichheit - mal sehen, wie es funktioniert.

Im folgenden Beispiel suchen wir nach Benutzern mit dem NamenEric.

Schauen wir uns unsere Datenbank an:

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

Schauen wir uns nun den Abfragecode an:

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

Diese Logik gibt erwartungsgemäß Folgendes zurück:

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

2.2. Regex

Eine flexiblere und leistungsfähigere Art der Abfrage ist der reguläre Ausdruck. Dieses c` ++ `wiederholt ein Kriterium unter Verwendung eines MongoDB$regex, das alle Datensätze zurückgibt, die für diesen regulären Ausdruck für dieses Feld geeignet sind.

Es funktioniert ähnlich wie die Operationen vonstartingWith, endingWith. Schauen wir uns ein Beispiel an.

Wir suchen jetzt nach allen Benutzern, deren Namen mitA beginnen.

Hier ist der Status der Datenbank:

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

Erstellen wir nun die Abfrage:

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

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

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

Hier ist ein weiteres kurzes Beispiel, diesmal nach allen Benutzern zu suchen, deren Namen mitc enden:

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

Das Ergebnis wird also sein:

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

2.3. Lt undgt

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

Schauen wir uns ein kurzes Beispiel an: Wir suchen alle Benutzer im Alter zwischen 20 und 50 Jahren.

Die Datenbank ist:

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

Dieser Abfragecode:

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

Und das Ergebnis - alle Benutzer, die mit einem Alter von mehr als 20 und weniger als 50 Jahren:

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

2.4. Sort

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

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

Erstens - hier sind die vorhandenen Daten:

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

Nach dem Ausführen vonsort:

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

Und hier ist das Ergebnis der Abfrage - gut sortiert nachage:

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

2.5. Pageable

Schauen wir uns ein kurzes Beispiel mit Paginierung an.

Hier ist der Status der Datenbank:

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

Nun die Abfragelogik, einfach nach einer Seite der Größe 2 fragen:

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.example.model.User",
        "name" : "Eric",
        "age" : 45
    },
    {
        "_id" : ObjectId("55c0e5e5511f0a164a581908"),
        "_class" : "org.example.model.User",
        "name" : "Antony",
        "age" : 33
    }
]

3. Generierte Abfragemethoden

Lassen Sie uns nun den allgemeineren Abfragetyp untersuchen, den Spring Data normalerweise bereitstellt - automatisch generierte Abfragen aus Methodennamen.

Das einzige, was wir tun müssen, um diese Art von Abfragen zu nutzen, ist die Deklaration der Methode in der Repository-Schnittstelle:

public interface UserRepository
  extends MongoRepository, QueryDslPredicateExecutor {
    ...
}

3.1. FindByX

Wir beginnen einfach mit der Untersuchung des Abfragetyps findBy. In diesem Fall suchen Sie nach Namen: __

List findByName(String name);

Wie im vorherigen Abschnitt - 2.1 - hat die Abfrage die gleichen Ergebnisse und findet alle Benutzer mit dem angegebenen Namen:

List users = userRepository.findByName("Eric");

3.2. StartingWith und endend mit.

In 2.2 haben wir eine aufregexbasierende Abfrage untersucht. Anfang und Ende mit sind natürlich weniger leistungsfähig, aber dennoch sehr nützlich - insbesondere, wenn wir sie nicht tatsächlich implementieren müssen.

Hier ist ein kurzes Beispiel, wie die Operationen aussehen würden: __

List findByNameStartingWith(String regexp);
List findByNameEndingWith(String regexp);

Das Beispiel, dies tatsächlich zu verwenden, wäre natürlich sehr einfach:

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

Und die Ergebnisse sind genau die gleichen.

3.3. Between

Ähnlich wie bei 2.3 werden alle Benutzer mit einem Alter zwischenageGT undageLT: zurückgegeben

List findByAgeBetween(int ageGT, int ageLT);

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

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

3.4. Like undOrderBy

Schauen wir uns diesmal ein erweitertes Beispiel an: Kombinieren Sie zwei Arten von Modifikatoren für die generierte Abfrage.

Wir werden nach allen Benutzern suchen, deren Namen den BuchstabenA enthalten, und wir werden die Ergebnisse auch nach Alter in aufsteigender Reihenfolge sortieren:

List users = userRepository.findByNameLikeOrderByAgeAsc("A");

Für die in 2.4 verwendete Datenbank lautet das Ergebnis:

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

4. JSON-Abfragemethoden

Wenn wir eine Abfrage nicht mithilfe eines Methodennamens oder von Kriterien darstellen können, können wir etwas niedrigeres tun -use the @Query annotation.

Mit dieser Annotation können wir eine unformatierte Abfrage als Mongo JSON-Abfragezeichenfolge angeben.

4.1. FindBy

Beginnen wir einfach und schauen wir uns an, wie wir zuersta find by type of methoddarstellen würden:

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

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

List users = userRepository.findUsersByName("Eric");

4.2 $regex

Schauen wir uns aucha regex driven query an - was natürlich das gleiche Ergebnis wie in 2.2 und 3.2 liefert:

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

Die Verwendung ist auch genau gleich:

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

4.3. $lt und$gt

Implementieren wir nun die Abfrage lt undgt:

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

Nun, da die Methode zwei Parameter hat, referenzieren wir jeden dieser Parameter nach Index in der Rohabfrage:?0 und?1.

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

5. QueryDSL-Abfragen

MongoRepository hat eine gute Unterstützung für das ProjektQueryDSL - daher können wir diese nette, typsichere API auch hier nutzen.

5.1. Die Maven-Abhängigkeiten

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


    com.mysema.querydsl
    querydsl-mongodb
    3.6.6


    com.mysema.querydsl
    querydsl-apt
    3.6.6

5.2. Q-Klassen

QueryDSL verwendete Q-Klassen zum Erstellen von Abfragen. Da wir diese jedoch nicht wirklich von Hand erstellen möchten, istwe need to generate themirgendwie.

Wir werden das apt-maven-Plugin verwenden, um das zu tun:


    com.mysema.maven
    apt-maven-plugin
    1.1.3
    
        
            
                process
            
            
                target/generated-sources/java
                
                  org.springframework.data.mongodb.repository.support.MongoAnnotationProcessor
                
            
        
     

Schauen wir uns die KlasseUseran und konzentrieren uns dabei speziell auf die Annotation@QueryEntity:

@QueryEntity
@Document
public class User {

    @Id
    private String id;
    private String name;
    private Integer age;

    // standard getters and setters
}

Nach dem Ausführen desprocess-Ziels des Maven-Lebenszyklus (oder eines anderen Ziels danach) - das passende Pluginwill generate the new classes untertarget/generated-sources/java/\{your package structure}:

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

    private static final long serialVersionUID = ...;

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

    public final NumberPath 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 path) {
        super(path.getType(), path.getMetadata());
    }

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

Mit Hilfe dieser Klasse werden wir unsere Abfragen nicht erstellen.

Als Randnotiz: Wenn Sie Eclipse verwenden, wird durch die Einführung dieses Plugins die folgende Warnung in pom generiert:

Sie müssen build mit JDK ausführen oder tools.jar im Klassenpfad haben. Wenn dies während des Eclipse-Builds auftritt, stellen Sie sicher, dass Sie Eclipse auch unter JDK ausführen (com.mysema.maven: apt-maven-plugin: 1.1.3: process: default: generate-sources

Maveninstall funktioniert einwandfrei undQUser Klasse wird generiert, aber ein Plugin wird im POM hervorgehoben.

Eine schnelle Lösung besteht darin, manuell auf das JDK ineclipse.ini zu zeigen:

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

5.3. The New Repository

Jetzt müssen wir die QueryDSL-Unterstützung in unseren Repositorys aktivieren - dies geschieht einfach mitextending the QueryDslPredicateExecutor interface:

public interface UserRepository extends
  MongoRepository, QuerydslPredicateExecutor

5.4. Eq

Bei aktivierter Unterstützung sindlet’s now implement the same queries wie zuvor dargestellt.

Wir beginnen mit einer einfachen Gleichstellung:

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

5.5. StartingWith undEndingWith

In ähnlicher Weise implementieren wir die vorherigen Abfragen - und suchen Benutzer mit Namen, die mitA beginnen:

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

Und endend mitc:

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

Das Ergebnis ist dasselbe wie in 2.2, 3.2 oder 4.2.

5.6. Between

Die nächste Abfrage gibt Benutzer mit einem Alter zwischen 20 und 50 Jahren zurück - ähnlich wie in den vorherigen Abschnitten:

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

6. Fazit

In diesem Artikel haben wir die vielen Möglichkeiten untersucht, die wir mit Spring Data MongoDB abfragen können.

Es ist interessant, einen Schritt zurückzutreten und zu sehen, wie viele leistungsstarke Möglichkeiten wir haben, MongoDB abzufragen - von eingeschränkter Kontrolle bis hin zur vollständigen Kontrolle mit Rohabfragen.

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