sql >> Database teknologi >  >> NoSQL >> MongoDB

En guide til forespørgsler i Spring Data MongoDB

1. Oversigt

Denne vejledning vil fokusere på at opbygge forskellige typer af forespørgsler i Spring Data MongoDB .

Vi skal se på forespørgsler på dokumenter med Forespørgsel og Kriterier klasser, automatisk genererede forespørgselsmetoder, JSON-forespørgsler og QueryDSL.

For Maven-opsætningen, se vores introduktionsartikel.

2. Dokumentforespørgsel

En af de mere almindelige måder at forespørge MongoDB på med Spring Data er ved at bruge Query og Kriterier klasser, som meget tæt afspejler native operatorer.

2.1. Er

Dette er simpelthen et kriterium, der bruger ligestilling. Lad os se, hvordan det virker.

I det følgende eksempel leder vi efter brugere ved navn Eric .

Lad os se på vores database:

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

Lad os nu se på forespørgselskoden:

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

Som forventet returnerer denne logik:

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

2.2. Regex

En mere fleksibel og kraftfuld type forespørgsel er regex. Dette opretter et kriterium ved hjælp af en MongoDB $regex der returnerer alle poster, der er egnede til regex for dette felt.

Det fungerer på samme måde som startingWith og endingWith operationer.

I dette eksempel leder vi efter alle brugere, der har navne, der begynder med A .

Her er status for databasen:

[
    {
        "_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
    }
]

Lad os nu oprette forespørgslen:

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

Dette kører og returnerer 2 poster:

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

Her er endnu et hurtigt eksempel, denne gang på udkig efter alle brugere, der har navne, der slutter med c :

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

Så resultatet bliver:

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

2.3. Lt og gt

Disse operatører opretter et kriterium ved hjælp af $lt (mindre end) og $gt (større end) operatører.

Lad os tage et hurtigt eksempel, hvor vi leder efter alle brugere mellem 20 og 50 år.

Databasen er:

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

Forespørgselskoden:

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

Og resultaterne for alle brugere med en alder på over 20 og under 50:

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

2.4. Sorter

Sortér bruges til at angive en sorteringsrækkefølge for resultaterne.

Eksemplet nedenfor returnerer alle brugere sorteret efter alder i stigende rækkefølge.

Først, her er de eksisterende data:

[
    {
        "_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
    }
]

Efter at have udført sort :

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

Og her er resultatet af forespørgslen, pænt sorteret efter alder :

[
    {
        "_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. Kan søges

Lad os se på et hurtigt eksempel med paginering.

Her er status for databasen:

[
    {
        "_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
    }
]

Her er forespørgselslogikken, blot at bede om en side i størrelse 2:

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

Og resultatet, de 2 dokumenter, som forventet:

[
    {
        "_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. Genererede forespørgselsmetoder

Lad os nu udforske den mere almindelige type forespørgsel, som Spring Data normalt leverer, autogenererede forespørgsler ud fra metodenavne.

Det eneste, vi skal gøre for at udnytte denne slags forespørgsler, er at erklære metoden på lagergrænsefladen:

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

3.1. FindByX

Vi starter enkelt ved at udforske findBy-type forespørgsel. I dette tilfælde bruger vi find efter navn:

List<User> findByName(String name);

Ligesom i det foregående afsnit, 2.1, vil forespørgslen have de samme resultater og finde alle brugere med det angivne navn:

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

3.2. Starting With og endingWith

I afsnit 2.2 udforskede vi et regex baseret forespørgsel. Starter og slutter med er selvfølgelig mindre kraftfulde, men ikke desto mindre ret nyttige, især hvis vi ikke skal implementere dem rent faktisk.

Her er et hurtigt eksempel på, hvordan operationerne vil se ud:

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

Eksemplet med faktisk at bruge dette ville selvfølgelig være meget enkelt:

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

Og resultaterne er nøjagtig de samme.

3.3. Mellem

I lighed med afsnit 2.3 vil dette returnere alle brugere med alderen mellem ageGT og ageLT:

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

Kaldning af metoden vil resultere i, at nøjagtig de samme dokumenter bliver fundet:

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

3.4. Synes godt om og OrderBy

Lad os se på et mere avanceret eksempel denne gang, der kombinerer to typer modifikatorer til den genererede forespørgsel.

Vi vil lede efter alle brugere, der har navne, der indeholder bogstavet A, og vi vil også sortere resultaterne efter alder, i stigende rækkefølge:

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

For den database, vi brugte i afsnit 2.4, vil resultatet være:

[
    {
        "_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-forespørgselsmetoder

Hvis vi ikke kan repræsentere en forespørgsel ved hjælp af et metodenavn eller kriterier, kan vi gøre noget mere lavt niveau, brug @Query anmærkning .

Med denne annotation kan vi angive en rå forespørgsel som en Mongo JSON-forespørgselsstreng.

4.1. Find ved

Lad os starte enkelt og se på, hvordan vi ville repræsentere et find af type metode først:

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

Denne metode bør returnere brugere ved navn. Pladsholderen ?0 refererer til metodens første parameter.

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

4.2. $regex

Vi kan også se på en regex-drevet forespørgsel hvilket naturligvis giver samme resultat som i afsnit 2.2 og 3.2:

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

Brugen er også nøjagtig den samme:

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

4.3. $lt og $gt

Lad os nu implementere lt og gt forespørgsel:

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

Nu hvor metoden har 2 parametre, refererer vi hver af disse efter indeks i den rå forespørgsel, ?0 og ?1:

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

5. QueryDSL-forespørgsler

MongoRepository har god support til QueryDSL-projektet, så vi kan også udnytte den fine, typesikre API her.

5.1. The Maven Dependencies

Lad os først sikre os, at vi har de korrekte Maven-afhængigheder defineret i pom:

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

QueryDSL brugte Q-klasser til at oprette forespørgsler, men da vi egentlig ikke ønsker at oprette disse i hånden, skal vi generere dem på en eller anden måde.

Vi kommer til at bruge apt-maven-plugin til at gøre det:

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

Lad os se på Brugeren klasse, der fokuserer specifikt på @QueryEntity anmærkning:

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

Efter at have kørt processen målet for Mavens livscyklus (eller ethvert andet mål efter det), vil apt-plugin'et generere de nye klasser under target/generated-sources/java/{din pakkestruktur} :

/**
 * 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);
    }
}

Det er på grund af denne klasse, at vi ikke behøver at oprette vores forespørgsler.

Som en sidebemærkning, hvis vi bruger Eclipse, vil introduktionen af ​​dette plugin generere følgende advarsel i pom:

Maveninstallationen fungerer fint, og QUser klasse genereres, men et plugin er fremhævet i pom.

En hurtig løsning er manuelt at pege på JDK i eclipse.ini :

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

5.3. Det nye lager

Nu skal vi faktisk aktivere QueryDSL-understøttelse i vores repositories, hvilket gøres ved blot at udvide QueryDslPredicateExecutor grænseflade :

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

5.4. Eq

Med support aktiveret lad os nu implementere de samme forespørgsler som dem, vi illustrerede før.

Vi starter med simpel lighed:

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

5.5. Starting With og EndingWith

Lad os på samme måde implementere de tidligere forespørgsler og finde brugere med navne, der starter med A :

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

Samt slutter med c :

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

Resultatet er det samme som i afsnit 2.2, 3.2 og 4.2.

5.6. Mellem

Den næste forespørgsel vil returnere brugere i alderen mellem 20 og 50, svarende til de foregående afsnit:

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

  1. MongoDB C#:ID-serialisering bedste mønster

  2. Ved at bruge MongoDB som vores masterdatabase, skal jeg så bruge en separat grafdatabase til at implementere relationer mellem enheder?

  3. Sådan eksporteres MongoDB-forespørgselsresultater til en CSV-fil

  4. Hvordan indsætter man milliarder af data til Redis effektivt?