1. Tổng quan
Hướng dẫn này sẽ tập trung vào việc xây dựng các loại truy vấn khác nhau trong Spring Data MongoDB .
Chúng tôi sẽ xem xét truy vấn tài liệu bằng Truy vấn và Tiêu chí các lớp, phương thức truy vấn được tạo tự động, truy vấn JSON và QueryDSL.
Để biết cách thiết lập Maven, hãy xem bài viết giới thiệu của chúng tôi.
2. Truy vấn tài liệu
Một trong những cách phổ biến hơn để truy vấn MongoDB với Dữ liệu mùa xuân là sử dụng Truy vấn và Tiêu chí các lớp, phản ánh rất chặt chẽ các toán tử gốc.
2.1. Là
Đây chỉ đơn giản là một tiêu chí sử dụng bình đẳng. Hãy xem nó hoạt động như thế nào.
Trong ví dụ sau, chúng tôi sẽ tìm kiếm những người dùng có tên là Eric .
Hãy xem cơ sở dữ liệu của chúng tôi:
[
{
"_id" : ObjectId("55c0e5e5511f0a164a581907"),
"_class" : "org.baeldung.model.User",
"name" : "Eric",
"age" : 45
},
{
"_id" : ObjectId("55c0e5e5511f0a164a581908"),
"_class" : "org.baeldung.model.User",
"name" : "Antony",
"age" : 55
}
}
Bây giờ hãy xem mã truy vấn:
Query query = new Query();
query.addCriteria(Criteria.where("name").is("Eric"));
List<User> users = mongoTemplate.find(query, User.class);
Như mong đợi, logic này trả về:
{
"_id" : ObjectId("55c0e5e5511f0a164a581907"),
"_class" : "org.baeldung.model.User",
"name" : "Eric",
"age" : 45
}
2.2. Regex
Một loại truy vấn linh hoạt và mạnh mẽ hơn là regex. Điều này tạo ra một tiêu chí bằng cách sử dụng MongoDB $ regex trả về tất cả các bản ghi phù hợp với regex cho trường này.
Nó hoạt động tương tự như startedWith và endingWith hoạt động.
Trong ví dụ này, chúng tôi sẽ tìm kiếm tất cả người dùng có tên bắt đầu bằng A .
Đây là trạng thái của cơ sở dữ liệu:
[
{
"_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
}
]
Bây giờ hãy tạo truy vấn:
Query query = new Query();
query.addCriteria(Criteria.where("name").regex("^A"));
List<User> users = mongoTemplate.find(query,User.class);
Thao tác này chạy và trả về 2 bản ghi:
[
{
"_id" : ObjectId("55c0e5e5511f0a164a581908"),
"_class" : "org.baeldung.model.User",
"name" : "Antony",
"age" : 33
},
{
"_id" : ObjectId("55c0e5e5511f0a164a581909"),
"_class" : "org.baeldung.model.User",
"name" : "Alice",
"age" : 35
}
]
Đây là một ví dụ nhanh khác, lần này tìm kiếm tất cả người dùng có tên kết thúc bằng c :
Query query = new Query();
query.addCriteria(Criteria.where("name").regex("c$"));
List<User> users = mongoTemplate.find(query, User.class);
Vì vậy, kết quả sẽ là:
{
"_id" : ObjectId("55c0e5e5511f0a164a581907"),
"_class" : "org.baeldung.model.User",
"name" : "Eric",
"age" : 45
}
2.3. Lt và gt
Các toán tử này tạo tiêu chí bằng cách sử dụng $ lt (nhỏ hơn) và $ gt (lớn hơn) toán tử.
Hãy lấy một ví dụ nhanh mà chúng tôi đang tìm kiếm tất cả người dùng trong độ tuổi từ 20 đến 50.
Cơ sở dữ liệu là:
[
{
"_id" : ObjectId("55c0e5e5511f0a164a581907"),
"_class" : "org.baeldung.model.User",
"name" : "Eric",
"age" : 45
},
{
"_id" : ObjectId("55c0e5e5511f0a164a581908"),
"_class" : "org.baeldung.model.User",
"name" : "Antony",
"age" : 55
}
}
Mã truy vấn:
Query query = new Query();
query.addCriteria(Criteria.where("age").lt(50).gt(20));
List<User> users = mongoTemplate.find(query,User.class);
Và kết quả cho tất cả người dùng có độ tuổi lớn hơn 20 và dưới 50:
{
"_id" : ObjectId("55c0e5e5511f0a164a581907"),
"_class" : "org.baeldung.model.User",
"name" : "Eric",
"age" : 45
}
2.4. Sắp xếp
Sắp xếp được sử dụng để chỉ định thứ tự sắp xếp cho các kết quả.
Ví dụ dưới đây trả về tất cả người dùng được sắp xếp theo độ tuổi theo thứ tự tăng dần.
Đầu tiên, đây là dữ liệu hiện có:
[
{
"_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
}
]
Sau khi thực hiện sắp xếp :
Query query = new Query();
query.with(Sort.by(Sort.Direction.ASC, "age"));
List<User> users = mongoTemplate.find(query,User.class);
Và đây là kết quả của truy vấn, được sắp xếp độc đáo theo tuổi :
[
{
"_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. Pagable
Hãy xem một ví dụ nhanh bằng cách sử dụng phân trang.
Đây là trạng thái của cơ sở dữ liệu:
[
{
"_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
}
]
Bây giờ đây là logic truy vấn, chỉ cần yêu cầu một trang có kích thước 2:
final Pageable pageableRequest = PageRequest.of(0, 2);
Query query = new Query();
query.with(pageableRequest);
Và kết quả, 2 tài liệu, như mong đợi:
[
{
"_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. Phương thức truy vấn đã tạo
Bây giờ chúng ta hãy khám phá loại truy vấn phổ biến hơn mà Spring Data thường cung cấp, các truy vấn được tạo tự động ngoài tên phương thức.
Điều duy nhất chúng ta cần làm để tận dụng các loại truy vấn này là khai báo phương thức trên giao diện kho lưu trữ:
public interface UserRepository
extends MongoRepository<User, String>, QueryDslPredicateExecutor<User> {
...
}
3.1. FindByX
Chúng ta sẽ bắt đầu đơn giản, bằng cách khám phá loại truy vấn findBy. Trong trường hợp này, chúng tôi sẽ sử dụng tìm theo tên:
List<User> findByName(String name);
Cũng giống như trong phần trước, 2.1, truy vấn sẽ có cùng kết quả, tìm tất cả người dùng có tên đã cho:
List<User> users = userRepository.findByName("Eric");
3.2. Bắt đầu với và endingWith
Trong phần 2.2, chúng tôi đã khám phá một regex truy vấn dựa trên. Bắt đầu và kết thúc tất nhiên là kém mạnh mẽ hơn, nhưng vẫn khá hữu ích, đặc biệt nếu chúng ta không thực sự phải triển khai chúng.
Dưới đây là một ví dụ nhanh về các hoạt động sẽ trông như thế nào:
List<User> findByNameStartingWith(String regexp);
List<User> findByNameEndingWith(String regexp);
Tất nhiên, ví dụ thực sự sử dụng điều này sẽ rất đơn giản:
List<User> users = userRepository.findByNameStartingWith("A");
List<User> users = userRepository.findByNameEndingWith("c");
Và kết quả hoàn toàn giống nhau.
3.3. Giữa
Tương tự như phần 2.3, điều này sẽ trả về tất cả người dùng có độ tuổi từ ageGT và ageLT:
List<User> findByAgeBetween(int ageGT, int ageLT);
Việc gọi phương thức sẽ dẫn đến việc tìm thấy chính xác các tài liệu giống nhau:
List<User> users = userRepository.findByAgeBetween(20, 50);
3.4. Thích và OrderBy
Chúng ta hãy xem xét một ví dụ nâng cao hơn lần này, kết hợp hai loại công cụ sửa đổi cho truy vấn đã tạo.
Chúng tôi sẽ tìm kiếm tất cả người dùng có tên chứa chữ cái A, và chúng tôi cũng sẽ sắp xếp kết quả theo độ tuổi, theo thứ tự tăng dần:
List<User> users = userRepository.findByNameLikeOrderByAgeAsc("A");
Đối với cơ sở dữ liệu chúng tôi đã sử dụng trong phần 2.4, kết quả sẽ là:
[
{
"_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. Phương thức truy vấn JSON
Nếu chúng tôi không thể biểu diễn một truy vấn với sự trợ giúp của tên phương thức hoặc tiêu chí, chúng tôi có thể thực hiện điều gì đó ở mức thấp hơn, sử dụng @Query chú thích .
Với chú thích này, chúng tôi có thể chỉ định một truy vấn thô dưới dạng chuỗi truy vấn Mongo JSON.
4.1. FindBy
Hãy bắt đầu đơn giản và xem xét cách chúng tôi đại diện cho a find by loại phương pháp đầu tiên:
@Query("{ 'name' : ?0 }")
List<User> findUsersByName(String name);
Phương thức này sẽ trả về người dùng theo tên. Trình giữ chỗ ? 0 tham chiếu đến tham số đầu tiên của phương thức.
List<User> users = userRepository.findUsersByName("Eric");
4.2. $ regex
Chúng tôi cũng có thể xem xét truy vấn theo hướng regex, tất nhiên cái nào tạo ra kết quả tương tự như trong phần 2.2 và 3.2:
@Query("{ 'name' : { $regex: ?0 } }")
List<User> findUsersByRegexpName(String regexp);
Cách sử dụng cũng hoàn toàn giống nhau:
List<User> users = userRepository.findUsersByRegexpName("^A");
List<User> users = userRepository.findUsersByRegexpName("c$");
4.3. $ lt và $ gt
Bây giờ, hãy triển khai lt và gt truy vấn:
@Query("{ 'age' : { $gt: ?0, $lt: ?1 } }")
List<User> findUsersByAgeBetween(int ageGT, int ageLT);
Bây giờ phương thức có 2 tham số, chúng tôi đang tham chiếu từng tham số này theo chỉ mục trong truy vấn thô, ? 0 và ? 1:
List<User> users = userRepository.findUsersByAgeBetween(20, 50);
5. Truy vấnDSL Truy vấn
MongoRepository có hỗ trợ tốt cho dự án QueryDSL, vì vậy chúng tôi cũng có thể tận dụng API tốt, an toàn về kiểu chữ đó tại đây.
5.1. Sự phụ thuộc của Maven
Đầu tiên, hãy đảm bảo rằng chúng ta có các phụ thuộc Maven chính xác được xác định trong 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 -các lớp
QueryDSL đã sử dụng các lớp Q để tạo các truy vấn, nhưng vì chúng tôi không thực sự muốn tạo các truy vấn này theo cách thủ công, chúng tôi cần tạo chúng bằng cách nào đó.
Chúng tôi sẽ sử dụng apt-maven-plugin để làm điều đó:
<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>
Hãy xem xét Người dùng , tập trung đặc biệt vào @QueryEntity chú thích:
@QueryEntity
@Document
public class User {
@Id
private String id;
private String name;
private Integer age;
// standard getters and setters
}
Sau khi chạy quá trình mục tiêu của vòng đời Maven (hoặc bất kỳ mục tiêu nào khác sau vòng đời đó), plugin apt sẽ tạo các lớp mới trong target / created-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);
}
}
Chính vì lớp này mà chúng ta không cần tạo các truy vấn của mình.
Lưu ý thêm, nếu chúng tôi đang sử dụng Eclipse, việc giới thiệu plugin này sẽ tạo ra cảnh báo sau trong pom:
The Maven cài đặt hoạt động tốt và QUser lớp được tạo, nhưng một plugin được đánh dấu trong pom.
Cách khắc phục nhanh chóng là trỏ đến JDK theo cách thủ công trong eclipse.ini :
...
-vm
{path_to_jdk}\jdk{your_version}\bin\javaw.exe
5.3. Kho lưu trữ mới
Bây giờ, chúng tôi cần thực sự bật hỗ trợ QueryDSL trong kho lưu trữ của mình, điều này được thực hiện đơn giản bằng cách mở rộng QueryDslPredicateExecutor giao diện :
public interface UserRepository extends
MongoRepository<User, String>, QuerydslPredicateExecutor<User>
5.4. Phương trình
Khi hỗ trợ được bật, bây giờ hãy triển khai các truy vấn tương tự như những cái chúng tôi đã minh họa trước đây.
Chúng ta sẽ bắt đầu với sự bình đẳng đơn giản:
QUser qUser = new QUser("user");
Predicate predicate = qUser.name.eq("Eric");
List<User> users = (List<User>) userRepository.findAll(predicate);
5.5. Bắt đầu với và EndingWith
Tương tự, hãy triển khai các truy vấn trước đó và tìm người dùng có tên bắt đầu bằng A :
QUser qUser = new QUser("user");
Predicate predicate = qUser.name.startsWith("A");
List<User> users = (List<User>) userRepository.findAll(predicate);
Cũng như kết thúc bằng c :
QUser qUser = new QUser("user");
Predicate predicate = qUser.name.endsWith("c");
List<User> users = (List<User>) userRepository.findAll(predicate);
Kết quả tương tự như trong phần 2.2, 3.2 và 4.2.
5.6. Giữa
Truy vấn tiếp theo sẽ trả về những người dùng có độ tuổi từ 20 đến 50, tương tự như các phần trước:
QUser qUser = new QUser("user");
Predicate predicate = qUser.age.between(20, 50);
List<User> users = (List<User>) userRepository.findAll(predicate);