MongoDB
 sql >> база данни >  >> NoSQL >> MongoDB

Ръководство за заявки в Spring Data MongoDB

1. Прегледа

Този урок ще се фокусира върху изграждането на различни типове заявки в Spring Data MongoDB .

Ще разгледаме заявките за документи с Query и Критерии класове, автоматично генерирани методи на заявка, JSON заявки и QueryDSL.

За настройката на Maven, разгледайте нашата уводна статия.

2. Запитване за документи

Един от най-често срещаните начини за запитване на MongoDB с Spring Data е като се използва Заявката и Критерии класове, които много точно отразяват родните оператори.

2.1. Е

Това е просто критерий, използващ равенството. Нека видим как работи.

В следващия пример ще търсим потребители на име Ерик .

Нека разгледаме нашата база данни:

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

Сега нека разгледаме кода на заявката:

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

Както се очаква, тази логика връща:

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

2.2. Регулярен израз

По-гъвкав и мощен тип заявка е регулярният израз. Това създава критерий с помощта на MongoDB $regex който връща всички записи, подходящи за регулярния израз за това поле.

Работи подобно на startingWith и завършва с операции.

В този пример ще търсим всички потребители, чиито имена започват с A .

Ето състоянието на базата данни:

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

Сега нека създадем заявката:

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

Това се изпълнява и връща 2 записа:

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

Ето още един бърз пример, този път търсим всички потребители, чиито имена завършват на c :

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

Така че резултатът ще бъде:

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

2.3. Lt и gt

Тези оператори създават критерий с помощта на $lt (по-малко от) и $gt (по-голямо от) оператори.

Нека вземем бърз пример, когато търсим всички потребители на възраст между 20 и 50 години.

Базата данни е:

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

Кодът на заявката:

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

И резултатите за всички потребители на възраст над 20 и под 50:

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

2.4. Сортиране

Сортиране се използва за определяне на реда на сортиране на резултатите.

Примерът по-долу връща всички потребители, сортирани по възраст във възходящ ред.

Първо, ето съществуващите данни:

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

След изпълнение на сортиране :

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

А ето и резултата от заявката, добре сортиран по възраст :

[
    {
        "_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. Страница

Нека разгледаме бърз пример за използване на пагинация.

Ето състоянието на базата данни:

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

Сега ето логиката на заявката, просто да поискате страница с размер 2:

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

И резултатът, 2-та документа, както се очаква:

[
    {
        "_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. Генерирани методи на заявката

Сега нека разгледаме по-често срещания тип заявка, която Spring Data обикновено предоставя, автоматично генерирани заявки от имена на методи.

Единственото нещо, което трябва да направим, за да използваме тези видове заявки, е да декларираме метода в интерфейса на хранилището:

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

3.1. FindByX

Ще започнем просто, като изследваме findBy типа заявка. В този случай ще използваме find по име:

List<User> findByName(String name);

Точно както в предишния раздел, 2.1, заявката ще има същите резултати, намирайки всички потребители с дадено име:

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

3.2. Започвайки с и завършва с

В раздел 2.2 проучихме редовен израз базирана заявка. Разбира се, началото и краят са по-малко мощни, но въпреки това доста полезни, особено ако не се налага да ги прилагаме.

Ето един бърз пример за това как биха изглеждали операциите:

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

Примерът за действително използване на това, разбира се, би бил много прост:

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

И резултатите са абсолютно същите.

3.3. Между

Подобно на раздел 2.3, това ще върне всички потребители на възраст между ageGT и ageLT:

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

Извикването на метода ще доведе до намиране на точно същите документи:

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

3.4. Харесвам и Поръчай по

Нека този път да разгледаме по-разширен пример, комбиниращ два типа модификатори за генерираната заявка.

Ще търсим всички потребители, чиито имена съдържат буквата A, и също така ще подредим резултатите по възраст във възходящ ред:

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

За базата данни, която използвахме в раздел 2.4, резултатът ще бъде:

[
    {
        "_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 методи на заявката

Ако не можем да представим заявка с помощта на име на метод или критерии, можем да направим нещо по-ниско ниво, използвайте @Query анотацията .

С тази анотация можем да посочим необработена заявка като низ за заявка на Mongo JSON.

4.1. Намери по

Нека започнем просто и да разгледаме как бихме представили намерете чрез вид метода първо:

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

Този метод трябва да върне потребители по име. Заместителят ?0 препраща към първия параметър на метода.

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

4.2. $regex

Можем също да разгледаме заявка, управлявана от регулярни изрази, което, разбира се, дава същия резултат като в раздели 2.2 и 3.2:

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

Използването също е абсолютно същото:

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

4.3. $lt и $gt

Сега нека внедрим lt и gt заявка:

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

Сега, когато методът има 2 параметъра, ние се позоваваме на всеки от тях чрез индекс в необработената заявка, ?0 и ?1:

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

5. QueryDSL заявки

MongoRepository има добра поддръжка за проекта QueryDSL, така че можем да използваме този приятен, безопасен за тип API и тук.

5.1. Зависимостите на Maven

Първо, нека се уверим, че имаме правилните зависимости на Maven, дефинирани в 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 -класовете

QueryDSL използва Q-класове за създаване на заявки, но тъй като всъщност не искаме да ги създаваме на ръка, трябва да ги генерираме някак си.

Ще използваме 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>

Нека разгледаме Потребителя клас, като се фокусира конкретно върху @QueryEntity анотация:

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

След стартиране на процеса цел на жизнения цикъл на Maven (или всяка друга цел след тази), плъгинът apt ще генерира новите класове под target/generated-sources/java/{структурата на вашия пакет :

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

Поради този клас не е необходимо да създаваме своите заявки.

Като странична забележка, ако използваме Eclipse, въвеждането на този плъгин ще генерира следното предупреждение в pom:

Инсталирането на Maven работи добре и QUser клас се генерира, но плъгин е маркиран в pom.

Бързо решение е да посочите ръчно JDK в eclipse.ini :

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

5.3. Новото хранилище

Сега трябва действително да активираме поддръжката на QueryDSL в нашите хранилища, което се прави чрез просто разширяване на QueryDslPredicateExecutor интерфейса :

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

5.4. екв.

С активирана поддръжка, нека сега да приложим същите заявки като тези, които илюстрирахме преди.

Ще започнем с просто равенство:

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

5.5. Започвайки с и EndingWith

По същия начин, нека внедрим предишните заявки и да намерим потребители с имена, които започват с A :

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

Както и завършва с c :

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

Резултатът е същият като в раздели 2.2, 3.2 и 4.2.

5.6. Между

Следващата заявка ще върне потребители на възраст между 20 и 50 години, подобно на предишните раздели:

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

  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Възможно ли е да се получи единичен резултат в съвкупност?

  2. Не искам да започваш mongod с `sudo mongod`

  3. Как да създам MongoDB дъмп на моята база данни?

  4. Има ли еквивалент на NOW() в MongoDB

  5. Динамични ключове след $group by