在 MongoRepository<Customer,String> 中使用限制和跳过
Use limit and skip in MongoRepository<Customer,String>
我们正在开展一个从 mongoDB 获取数据的项目。我们已经创建了存储库 class,如下所示
@Repository
public interface CustomerRepository extends MongoRepository<Customer,String>{
List<Customer> customers = findByCustomerId(final String customerId);
}
我们希望添加 skip/offset 并限制参数以用作 findByCustomerId 方法的一部分。其中 limit 用于定义返回的记录数,skip/offset 定义我们需要获取记录的记录数。
请帮助我们如何使用 MongoRepository 以最佳方式实现这一点。
有两种方法可以做到这一点。
- 如本回答所述,使用
@Aggregation
注释。
例如:
@Repository
public interface CustomerRepository extends MongoRepository<Customer,String>{
@Aggregation(pipeline = {
"{ '$match': { 'customerId' : ?0 } }",
"{ '$sort' : { 'customerId' : 1 } }",
"{ '$skip' : ?1 }",
"{ '$limit' : ?2 }"
})
List<Customer> findByCustomerId(final String customerId, int skip, int limit);
@Aggregation(pipeline = {
"{ '$match': { 'customerId' : ?0 } }",
"{ '$sort' : { 'customerId' : 1 } }",
"{ '$skip' : ?1 }"
})
Page<Customer> findCustomers(final String customerId, int skip, Pageable pageable);
}
可能需要修改 $match
运算符的查询,以便更好地反映匹配文档需要满足的条件。
- 在查询方法中使用
Pageable
参数,并从调用 Repository 方法的层中提供 PageRequest
,如本答案所示。
对于问题中的代码片段,这就变成了。
@Repository
public interface CustomerRepository extends MongoRepository<Customer,String> {
Page<Customer> findByCustomerId(final String customerId, Pageable pageable);
}
// -------------------------------------------------------
// Call the repository method from a service
@Service
public class CustomerService {
private final CustomerRepository customerRepository;
public CustomerService(CustomerRepository customerRepository) {
this.customerRepository = customerRepository;
}
public List<Customer> getCustomers(String customerId, int skip, int limit) {
// application-specific handling of skip and limit arguments
int page = 1; // calculated based on skip and limit values
int size = 5; // calculated based on skip and limit values
Page<Customer> page = customerRepository.findByCustomerId(customerId,
PageRequest.of(page, size, Sort.Direction.ASC, "customerId"));
List<Customer> customers = page.getContent();
/*
Here, the query method will retrieve 5 documents from the second
page.
It skips the first 5 documents in the first page with page index 0.
This approach requires calculating the page to retrieve based on
the application's definition of limit/skip.
*/
return Collections.unmodifiableList(customers);
}
}
聚合方法更有用。
如果结果仅限于几个文档那么查询方式可以returnList<Customer>
。
如果有很多文档,那么查询方法可以修改为使用 Pageable
参数 returns Page<Customer>
来分页文档。
同时参考 Spring 数据和 MongoDB 文档。
https://docs.spring.io/spring-data/mongodb/docs/3.2.10/reference/html/#mongo.repositories
MongoDB 聚合 - https://www.mongodb.com/docs/manual/meta/aggregation-quick-reference/
动态查询
自定义 Spring 数据存储库实施以及 MongoTemplate
的使用应该有助于实施动态查询。
MongoTemplate
- https://docs.spring.io/spring-data/mongodb/docs/3.2.10/api/org/springframework/data/mongodb/core/MongoTemplate.html
一个简单的用例是使用带有查询和 SimpleMongoRepository 的自定义存储库 类。
CustomerRepository.java
@Repository
public interface CustomerRepository extends ResourceRepository<Customer, String> {
}
ResourceRepository.java
@NoRepositoryBean
public interface ResourceRepository<T, I> extends MongoRepository<T, I> {
Page<T> findAll(Query query, Pageable pageable);
}
ResourceRepositoryImpl.java
@SuppressWarnings("rawtypes")
public class ResourceRepositoryImpl<T, I> extends SimpleMongoRepository<T, I> implements ResourceRepository<T, I> {
private MongoOperations mongoOperations;
private MongoEntityInformation entityInformation;
public ResourceRepositoryImpl(final MongoEntityInformation entityInformation, final MongoOperations mongoOperations) {
super(entityInformation, mongoOperations);
this.entityInformation = entityInformation;
this.mongoOperations = mongoOperations;
}
@Override
public Page<T> findAll(final Query query, final Pageable pageable) {
Assert.notNull(query, "Query must not be null!");
long total = mongoOperations.count(query, entityInformation.getJavaType(), entityInformation.getCollectionName());
List<T> content = mongoOperations.find(query.with(pageable), entityInformation.getJavaType(), entityInformation.getCollectionName());
return new PageImpl<T>(content,pageable,total);
}
}
CustomerService.java
@RequiredArgsConstructor
@Service
public class CustomerService {
private final CustomerRepository repository;
/**
* @param customerId
* @param limit the size of the page to be returned, must be greater than 0.
* @param page zero-based page index, must not be negative.
* @return Page of {@link Customer}
*/
public Page<Customer> getCustomers(String customerId, int limit, int page) {
Query query = new Query();
query.addCriteria(Criteria.where("customerId").is(customerId));
return repository.findAll(query, PageRequest.of(page, limit, Sort.by(Sort.Direction.ASC, "customerId")));
}
public List<Customer> getCustomersList(String customerId, int limit, int page) {
Page<Customer> customerPage = getCustomers(customerId, limit, page);
return customerPage.getContent();
}
}
具有特定标准的参考:
https://dzone.com/articles/advanced-search-amp-filtering-api-using-spring-dat
我已经将聚合查询与 $skip 和 $limit 一起使用,它工作正常,并且在您需要对查询结果的复杂部分进行分页时非常有用。对于更简单的查询,我使用带有 Query 对象的 spring mongo 模板。查询对象采用 Pageable 对象,您可以在其中定义页码和页面大小以及排序选项。
Criteria criterion = Criteria.where("field").is("value");//build your criteria here.
Query query = new Query(criterion);
Sort fieldSorting = Sort.by(Sort.Direction.DESC, "sortField"); // sort field
int pageNo = 1; //which page you want to fetch. NoOfPages = TotalRecords/PageZie
int pagesize = 10; // no of records per page
Pageable pageable = PageRequest.of(pageNo, pagesize, fieldSorting); // define your page
mongoTemplate.find(query.with(pageable), Object.class); // provide appropriate DTO class to map.
对于 mongo 数据库聚合选项 - https://www.mongodb.com/docs/manual/reference/operator/aggregation/limit/
https://www.mongodb.com/docs/manual/reference/operator/aggregation/skip/
我们正在开展一个从 mongoDB 获取数据的项目。我们已经创建了存储库 class,如下所示
@Repository
public interface CustomerRepository extends MongoRepository<Customer,String>{
List<Customer> customers = findByCustomerId(final String customerId);
}
我们希望添加 skip/offset 并限制参数以用作 findByCustomerId 方法的一部分。其中 limit 用于定义返回的记录数,skip/offset 定义我们需要获取记录的记录数。
请帮助我们如何使用 MongoRepository 以最佳方式实现这一点。
有两种方法可以做到这一点。
- 如本回答所述,使用
@Aggregation
注释。
例如:
@Repository
public interface CustomerRepository extends MongoRepository<Customer,String>{
@Aggregation(pipeline = {
"{ '$match': { 'customerId' : ?0 } }",
"{ '$sort' : { 'customerId' : 1 } }",
"{ '$skip' : ?1 }",
"{ '$limit' : ?2 }"
})
List<Customer> findByCustomerId(final String customerId, int skip, int limit);
@Aggregation(pipeline = {
"{ '$match': { 'customerId' : ?0 } }",
"{ '$sort' : { 'customerId' : 1 } }",
"{ '$skip' : ?1 }"
})
Page<Customer> findCustomers(final String customerId, int skip, Pageable pageable);
}
可能需要修改 $match
运算符的查询,以便更好地反映匹配文档需要满足的条件。
- 在查询方法中使用
Pageable
参数,并从调用 Repository 方法的层中提供PageRequest
,如本答案所示。
对于问题中的代码片段,这就变成了。
@Repository
public interface CustomerRepository extends MongoRepository<Customer,String> {
Page<Customer> findByCustomerId(final String customerId, Pageable pageable);
}
// -------------------------------------------------------
// Call the repository method from a service
@Service
public class CustomerService {
private final CustomerRepository customerRepository;
public CustomerService(CustomerRepository customerRepository) {
this.customerRepository = customerRepository;
}
public List<Customer> getCustomers(String customerId, int skip, int limit) {
// application-specific handling of skip and limit arguments
int page = 1; // calculated based on skip and limit values
int size = 5; // calculated based on skip and limit values
Page<Customer> page = customerRepository.findByCustomerId(customerId,
PageRequest.of(page, size, Sort.Direction.ASC, "customerId"));
List<Customer> customers = page.getContent();
/*
Here, the query method will retrieve 5 documents from the second
page.
It skips the first 5 documents in the first page with page index 0.
This approach requires calculating the page to retrieve based on
the application's definition of limit/skip.
*/
return Collections.unmodifiableList(customers);
}
}
聚合方法更有用。
如果结果仅限于几个文档那么查询方式可以returnList<Customer>
。
如果有很多文档,那么查询方法可以修改为使用 Pageable
参数 returns Page<Customer>
来分页文档。
同时参考 Spring 数据和 MongoDB 文档。
https://docs.spring.io/spring-data/mongodb/docs/3.2.10/reference/html/#mongo.repositories
MongoDB 聚合 - https://www.mongodb.com/docs/manual/meta/aggregation-quick-reference/
动态查询
自定义 Spring 数据存储库实施以及 MongoTemplate
的使用应该有助于实施动态查询。
MongoTemplate
- https://docs.spring.io/spring-data/mongodb/docs/3.2.10/api/org/springframework/data/mongodb/core/MongoTemplate.html
一个简单的用例是使用带有查询和 SimpleMongoRepository 的自定义存储库 类。
CustomerRepository.java
@Repository
public interface CustomerRepository extends ResourceRepository<Customer, String> {
}
ResourceRepository.java
@NoRepositoryBean
public interface ResourceRepository<T, I> extends MongoRepository<T, I> {
Page<T> findAll(Query query, Pageable pageable);
}
ResourceRepositoryImpl.java
@SuppressWarnings("rawtypes")
public class ResourceRepositoryImpl<T, I> extends SimpleMongoRepository<T, I> implements ResourceRepository<T, I> {
private MongoOperations mongoOperations;
private MongoEntityInformation entityInformation;
public ResourceRepositoryImpl(final MongoEntityInformation entityInformation, final MongoOperations mongoOperations) {
super(entityInformation, mongoOperations);
this.entityInformation = entityInformation;
this.mongoOperations = mongoOperations;
}
@Override
public Page<T> findAll(final Query query, final Pageable pageable) {
Assert.notNull(query, "Query must not be null!");
long total = mongoOperations.count(query, entityInformation.getJavaType(), entityInformation.getCollectionName());
List<T> content = mongoOperations.find(query.with(pageable), entityInformation.getJavaType(), entityInformation.getCollectionName());
return new PageImpl<T>(content,pageable,total);
}
}
CustomerService.java
@RequiredArgsConstructor
@Service
public class CustomerService {
private final CustomerRepository repository;
/**
* @param customerId
* @param limit the size of the page to be returned, must be greater than 0.
* @param page zero-based page index, must not be negative.
* @return Page of {@link Customer}
*/
public Page<Customer> getCustomers(String customerId, int limit, int page) {
Query query = new Query();
query.addCriteria(Criteria.where("customerId").is(customerId));
return repository.findAll(query, PageRequest.of(page, limit, Sort.by(Sort.Direction.ASC, "customerId")));
}
public List<Customer> getCustomersList(String customerId, int limit, int page) {
Page<Customer> customerPage = getCustomers(customerId, limit, page);
return customerPage.getContent();
}
}
具有特定标准的参考: https://dzone.com/articles/advanced-search-amp-filtering-api-using-spring-dat
我已经将聚合查询与 $skip 和 $limit 一起使用,它工作正常,并且在您需要对查询结果的复杂部分进行分页时非常有用。对于更简单的查询,我使用带有 Query 对象的 spring mongo 模板。查询对象采用 Pageable 对象,您可以在其中定义页码和页面大小以及排序选项。
Criteria criterion = Criteria.where("field").is("value");//build your criteria here.
Query query = new Query(criterion);
Sort fieldSorting = Sort.by(Sort.Direction.DESC, "sortField"); // sort field
int pageNo = 1; //which page you want to fetch. NoOfPages = TotalRecords/PageZie
int pagesize = 10; // no of records per page
Pageable pageable = PageRequest.of(pageNo, pagesize, fieldSorting); // define your page
mongoTemplate.find(query.with(pageable), Object.class); // provide appropriate DTO class to map.
对于 mongo 数据库聚合选项 - https://www.mongodb.com/docs/manual/reference/operator/aggregation/limit/ https://www.mongodb.com/docs/manual/reference/operator/aggregation/skip/