sql >> Database >  >> NoSQL >> MongoDB

Een gids voor query's in Spring Data MongoDB

1. Overzicht

Deze tutorial is gericht op het bouwen van verschillende types queries in Spring Data MongoDB .

We gaan kijken naar het opvragen van documenten met Query en Criteria klassen, automatisch gegenereerde querymethoden, JSON-query's en QueryDSL.

Bekijk ons ​​inleidende artikel voor de Maven-configuratie.

2. Documenten opvragen

Een van de meest voorkomende manieren om MongoDB te bevragen met Spring Data is door gebruik te maken van de Query en Criteria klassen, die zeer nauw overeenkomen met native operators.

2.1. Is

Dit is gewoon een criterium dat gelijkheid gebruikt. Laten we eens kijken hoe het werkt.

In het volgende voorbeeld zoeken we naar gebruikers met de naam Eric .

Laten we eens kijken naar onze 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
    }
}

Laten we nu eens kijken naar de zoekcode:

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

Zoals verwacht, keert deze logica terug:

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

2.2. Regex

Een flexibeler en krachtiger type query is de regex. Dit creëert een criterium met behulp van een MongoDB $regex die alle records retourneert die geschikt zijn voor de regex voor dit veld.

Het werkt op dezelfde manier als startingWith en eindigendWith operaties.

In dit voorbeeld zoeken we naar alle gebruikers met namen die beginnen met A .

Hier is de staat van de database:

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

Laten we nu de query maken:

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

Dit wordt uitgevoerd en retourneert 2 records:

[
    {
        "_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 is nog een snel voorbeeld, dit keer op zoek naar alle gebruikers met namen die eindigen op c :

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

Het resultaat is dus:

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

2.3. Lt en gt

Deze operators creëren een criterium met behulp van de $lt (kleiner dan) en $gt (groter dan) operators.

Laten we een snel voorbeeld nemen waarbij we op zoek zijn naar alle gebruikers tussen de 20 en 50 jaar.

De database is:

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

De zoekcode:

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

En de resultaten voor alle gebruikers met een leeftijd van meer dan 20 en jonger dan 50:

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

2.4. Sorteren

Sorteren wordt gebruikt om een ​​sorteervolgorde voor de resultaten op te geven.

Het onderstaande voorbeeld retourneert alle gebruikers gesorteerd op leeftijd in oplopende volgorde.

Ten eerste, hier zijn de bestaande gegevens:

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

Na het uitvoeren van sorteren :

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

En hier is het resultaat van de zoekopdracht, netjes gesorteerd op leeftijd :

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

Laten we een snel voorbeeld bekijken met paginering.

Hier is de staat van de database:

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

Dit is de logica van de zoekopdracht, gewoon vragen om een ​​pagina met de grootte 2:

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

En het resultaat, de 2 documenten, zoals verwacht:

[
    {
        "_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. Gegenereerde querymethoden

Laten we nu eens kijken naar het meer algemene type query dat Spring Data gewoonlijk biedt, automatisch gegenereerde query's op basis van methodenamen.

Het enige dat we hoeven te doen om dit soort zoekopdrachten te benutten, is door de methode op de repository-interface te declareren:

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

3.1. FindByX

We beginnen eenvoudig door het type zoekopdracht te verkennen. In dit geval gebruiken we zoeken op naam:

List<User> findByName(String name);

Net als in de vorige sectie, 2.1, zal de zoekopdracht dezelfde resultaten hebben, waarbij alle gebruikers met de opgegeven naam worden gevonden:

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

3.2. Begin met en eindigendWith

In paragraaf 2.2 hebben we een regex gebaseerde vraag. Begint en eindigt met zijn natuurlijk minder krachtig, maar toch best handig, vooral als we ze niet echt hoeven te implementeren.

Hier is een snel voorbeeld van hoe de bewerkingen eruit zouden zien:

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

Het voorbeeld om dit daadwerkelijk te gebruiken zou natuurlijk heel eenvoudig zijn:

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

En de resultaten zijn precies hetzelfde.

3.3. Tussen

Net als bij sectie 2.3, retourneert dit alle gebruikers met een leeftijd tussen ageGT en ageLT:

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

Als u de methode aanroept, worden exact dezelfde documenten gevonden:

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

3.4. Vind ik leuk en OrderBy

Laten we deze keer eens kijken naar een meer geavanceerd voorbeeld, waarbij twee typen modifiers voor de gegenereerde zoekopdracht worden gecombineerd.

We gaan op zoek naar alle gebruikers met namen die de letter A, . bevatten en we gaan de resultaten ook sorteren op leeftijd, in oplopende volgorde:

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

Voor de database die we in paragraaf 2.4 hebben gebruikt, is het resultaat:

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

Als we een query niet kunnen weergeven met behulp van een methodenaam of criteria, kunnen we iets op een lager niveau doen, gebruik de @Query annotatie .

Met deze annotatie kunnen we een onbewerkte query specificeren als een Mongo JSON-querystring.

4.1. FindBy

Laten we eenvoudig beginnen en kijken hoe we een vondst door . zouden voorstellen type methode eerst:

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

Deze methode zou gebruikers op naam moeten retourneren. De tijdelijke aanduiding ?0 verwijst naar de eerste parameter van de methode.

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

4.2. $regex

We kunnen ook kijken naar een regex-gestuurde zoekopdracht, wat natuurlijk hetzelfde resultaat oplevert als in paragraaf 2.2 en 3.2:

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

Het gebruik is ook precies hetzelfde:

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

4.3. $lt en $gt

Laten we nu de lt en gt . implementeren vraag:

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

Nu de methode 2 parameters heeft, verwijzen we naar elk van deze door index in de onbewerkte zoekopdracht, ?0 en ?1:

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

5. QueryDSL-query's

MongoRepository heeft goede ondersteuning voor het QueryDSL-project, dus we kunnen die mooie, typeveilige API ook hier gebruiken.

5.1. De Maven-afhankelijkheden

Laten we er eerst voor zorgen dat we de juiste Maven-afhankelijkheden hebben gedefinieerd in de 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 -klassen

QueryDSL gebruikte Q-klassen voor het maken van queries, maar aangezien we deze niet echt met de hand willen maken, we moeten ze genereren op de een of andere manier.

We gaan de apt-maven-plugin gebruiken om dat te doen:

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

Laten we eens kijken naar de Gebruiker klasse, specifiek gericht op de @QueryEntity annotatie:

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

Na het uitvoeren van het proces doel van de Maven-levenscyclus (of een ander doel daarna), zal de apt-plug-in de nieuwe klassen genereren onder target/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<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);
    }
}

Het is vanwege deze klasse dat we onze query's niet hoeven te maken.

Als een kanttekening, als we Eclipse gebruiken, zal de introductie van deze plug-in de volgende waarschuwing in pom genereren:

De Maven-installatie werkt prima en de QUser class wordt gegenereerd, maar een plug-in is gemarkeerd in de pom.

Een snelle oplossing is om handmatig naar de JDK te verwijzen in eclipse.ini :

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

5.3. De nieuwe repository

Nu moeten we QueryDSL-ondersteuning daadwerkelijk inschakelen in onze repositories, wat gedaan wordt door simpelweg de QueryDslPredicateExecutor uit te breiden. interface :

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

5.4. Eq

Met ondersteuning ingeschakeld, laten we nu dezelfde zoekopdrachten implementeren zoals degene die we eerder hebben geïllustreerd.

We beginnen met eenvoudige gelijkheid:

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

5.5. Begin met en EndingWith

Laten we op dezelfde manier de vorige zoekopdrachten implementeren en gebruikers zoeken met namen die beginnen met A :

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

Evenals eindigend met c :

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

Het resultaat is hetzelfde als in paragraaf 2.2, 3.2 en 4.2.

5.6. Tussen

De volgende zoekopdracht levert gebruikers op met leeftijden tussen 20 en 50, vergelijkbaar met de vorige secties:

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

  1. Langzame zoekopdrachten analyseren in MongoDB

  2. Hoe zou Redis te weten komen of het gegevens in de cache of nieuwe gegevens uit DB moet retourneren?

  3. MongoDB SSPL-licentiewijzigingsupdate

  4. Hoe kunt u uw MongoDB-applicatie-upgrades testen?