sql >> Databasteknik >  >> NoSQL >> MongoDB

En guide till frågor i vårdata MongoDB

1. Översikt

Denna handledning kommer att fokusera på att bygga ut olika typer av frågor i Spring Data MongoDB .

Vi kommer att titta på att söka efter dokument med Query och Kriterier klasser, automatiskt genererade frågemetoder, JSON-frågor och QueryDSL.

För Maven-installationen, ta en titt på vår inledande artikel.

2. Dokumentfråga

Ett av de vanligaste sätten att fråga MongoDB med Spring Data är att använda Query och Kriterier klasser, som mycket nära speglar inhemska operatorer.

2.1. Är

Detta är helt enkelt ett kriterium som använder jämlikhet. Låt oss se hur det fungerar.

I följande exempel kommer vi att leta efter användare som heter Eric .

Låt oss titta på vår databas:

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

Låt oss nu titta på frågekoden:

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

Som förväntat returnerar denna logik:

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

2.2. Regex

En mer flexibel och kraftfull typ av fråga är regex. Detta skapar ett kriterium med en MongoDB $regex som returnerar alla poster som är lämpliga för regex för detta fält.

Det fungerar på samma sätt som startingWith och endingWith operationer.

I det här exemplet letar vi efter alla användare som har namn som börjar med A .

Här är tillståndet för 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
    }
]

Låt oss nu skapa frågan:

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

Detta kör och returnerar 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
    }
]

Här är ett annat snabbt exempel, den här gången letar du efter alla användare som har namn som slutar med c :

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

Så resultatet blir:

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

2.3. Lt och gt

Dessa operatorer skapar ett kriterium med $lt (mindre än) och $gt (större än) operatörer.

Låt oss ta ett snabbt exempel där vi letar efter alla användare mellan 20 och 50 år.

Databasen är:

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

Frågekoden:

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

Och resultaten för alla användare med en ålder över 20 och under 50:

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

2.4. Sortera

Sortera används för att ange en sorteringsordning för resultaten.

Exemplet nedan returnerar alla användare sorterade efter ålder i stigande ordning.

Först, här är befintliga 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 att ha utfört sortera :

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

Och här är resultatet av frågan, snyggt sorterat efter ålder :

[
    {
        "_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. Sökbar

Låt oss titta på ett snabbt exempel med paginering.

Här är tillståndet för 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
    }
]

Nu är det här frågelogiken, att bara be om en sida i storlek 2:

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

Och resultatet, de 2 dokumenten, som förväntat:

[
    {
        "_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. Genererade frågemetoder

Låt oss nu utforska den vanligare typen av fråga som Spring Data vanligtvis tillhandahåller, automatiskt genererade frågor av metodnamn.

Det enda vi behöver göra för att utnyttja den här typen av frågor är att deklarera metoden i förvarets gränssnitt:

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

3.1. FindByX

Vi börjar enkelt genom att utforska söktypen findBy. I det här fallet använder vi sök efter namn:

List<User> findByName(String name);

Precis som i föregående avsnitt, 2.1, kommer frågan att få samma resultat och hitta alla användare med det angivna namnet:

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

3.2. Börjar med och endingWith

I avsnitt 2.2 utforskade vi ett regex baserad fråga. Börjar och slutar med är naturligtvis mindre kraftfulla, men ändå ganska användbara, särskilt om vi inte behöver implementera dem faktiskt.

Här är ett snabbt exempel på hur operationerna skulle se ut:

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

Exemplet på att faktiskt använda detta skulle naturligtvis vara väldigt enkelt:

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

Och resultaten är exakt desamma.

3.3. Mellan

I likhet med avsnitt 2.3 kommer detta att returnera alla användare med ålder mellan ageGT och ageLT:

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

Att anropa metoden kommer att resultera i att exakt samma dokument hittas:

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

3.4. Gilla och OrderBy

Låt oss ta en titt på ett mer avancerat exempel den här gången, som kombinerar två typer av modifierare för den genererade frågan.

Vi kommer att leta efter alla användare som har namn som innehåller bokstaven A, och vi kommer också att sortera resultaten efter ålder, i stigande ordning:

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

För databasen vi använde i avsnitt 2.4 blir resultatet:

[
    {
        "_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-frågemetoder

Om vi ​​inte kan representera en fråga med hjälp av ett metodnamn eller kriterium kan vi göra något mer på låg nivå, använd @Query anteckning .

Med den här kommentaren kan vi ange en råfråga som en Mongo JSON-frågesträng.

4.1. Sök efter

Låt oss börja enkelt och titta på hur vi skulle representera ett hitt av typ av metod först:

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

Denna metod bör returnera användare med namn. Platshållaren ?0 refererar till den första parametern i metoden.

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

4.2. $regex

Vi kan också titta på en regex-driven fråga, vilket givetvis ger samma resultat som i avsnitt 2.2 och 3.2:

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

Användningen är också exakt densamma:

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

4.3. $lt och $gt

Låt oss nu implementera lt och gt fråga:

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

Nu när metoden har 2 parametrar hänvisar vi till var och en av dessa efter index i den råa frågan, ?0 och ?1:

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

5. QueryDSL-frågor

MongoRepository har bra stöd för QueryDSL-projektet, så vi kan utnyttja det trevliga, typsäkra API här också.

5.1. The Maven Dependencies

Låt oss först se till att vi har rätt Maven-beroenden definierade 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 använde Q-klasser för att skapa frågor, men eftersom vi egentligen inte vill skapa dessa för hand måste vi generera dem på något sätt.

Vi kommer att använda apt-maven-plugin för att göra 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>

Låt oss titta på Användaren klass, med fokus specifikt på @QueryEntity anteckning:

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

Efter att ha kört processen mål för Mavens livscykel (eller något annat mål efter det), apt-pluginen kommer att generera de nya klasserna under target/generated-sources/java/{din 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);
    }
}

Det är på grund av den här klassen som vi inte behöver skapa våra frågor.

Som en sidoanteckning, om vi använder Eclipse, kommer introduktionen av detta plugin att generera följande varning i pom:

Maveninstallationen fungerar bra och QUser klass genereras, men ett plugin är markerat i pom.

En snabb lösning är att manuellt peka på JDK i eclipse.ini :

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

5.3. Det nya förrådet

Nu måste vi faktiskt aktivera QueryDSL-stöd i våra arkiv, vilket görs genom att helt enkelt förlänga QueryDslPredicateExecutor gränssnitt :

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

5.4. Ekv.

Med stöd aktiverat låt oss nu implementera samma frågor som de vi illustrerat tidigare.

Vi börjar med enkel jämlikhet:

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

5.5. Börjar med och EndingWith

På samma sätt, låt oss implementera de tidigare frågorna och hitta användare med namn som börjar med A :

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

Samt slutar med c :

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

Resultatet är detsamma som i avsnitt 2.2, 3.2 och 4.2.

5.6. Mellan

Nästa fråga kommer att returnera användare i åldrarna mellan 20 och 50, liknande de föregående avsnitten:

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

  1. Så här gör du:Testa HBase-applikationer med populära verktyg

  2. Är det dåligt att ändra _id-typ i MongoDB till heltal?

  3. ScaleGrid Hosting lägger till stöd för högt tillgängliga Redis™-kluster med automatisk delning

  4. Azure Redis cache - timeouts på GET-samtal