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