mongodb 在MongoRepository〈Customer,String>中使用限制和跳过

uujelgoq  于 2022-11-22  发布在  Go
关注(0)|答案(4)|浏览(210)

我们正在做一个从mongoDB获取数据的项目。

@Repository
public interface CustomerRepository extends MongoRepository<Customer,String>{
     List<Customer> customers = findByCustomerId(final String customerId);
}

我们希望添加skip/offset和limit参数,以用作findByCustomerId方法的一部分。其中limit用于定义返回的记录数,skip/offset用于定义记录数,在此之后我们需要获取记录。
请帮助我们如何使用MongoRepository以最好的方式实现这一点。

7rfyedvj

7rfyedvj1#

有两种方法可以做到这一点。
1.使用此答案中提到的@Aggregation注解。https://stackoverflow.com/a/71292598/8470055
例如:

@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运算符的查询,以便它更好地反映匹配文档需要满足的条件。
1.在query方法中使用Pageable参数,并提供调用Repository方法的层中的PageRequest,如下答案所示。https://stackoverflow.com/a/10077534/8470055
对于问题中的代码片段,则变为。

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

聚合方法更有用。如果结果仅限于几个文档,那么查询方法可以返回List<Customer>。如果有很多文档,那么查询方法可以修改为使用Pageable参数,该参数返回Page<Customer>,以便对文档进行分页。
请参阅Spring Data 和MongoDB文档。
https://docs.spring.io/spring-data/mongodb/docs/3.2.10/reference/html/#mongo.repositories
https://docs.spring.io/spring-data/mongodb/docs/3.2.10/reference/html/#mongodb.repositories.queries.aggregation
https://docs.spring.io/spring-data/mongodb/docs/3.2.10/api/org/springframework/data/mongodb/repository/Aggregation.html
https://docs.spring.io/spring-data/commons/docs/current/api/org/springframework/data/domain/Pageable.html
https://docs.spring.io/spring-data/commons/docs/current/api/org/springframework/data/domain/PageRequest.html
MongoDB聚合-https://www.mongodb.com/docs/manual/meta/aggregation-quick-reference/

动态查询

自定义SpringData存储库实现沿着MongoTemplate的使用应该有助于实现动态查询。
自定义存储库-https://docs.spring.io/spring-data/mongodb/docs/3.2.10/reference/html/#repositories.custom-implementations
MongoTemplatehttps://docs.spring.io/spring-data/mongodb/docs/3.2.10/api/org/springframework/data/mongodb/core/MongoTemplate.html

brgchamk

brgchamk2#

一个简单的用例是使用带有Query和SimpleMongoRepository类的自定义存储库。

客户信息库.java

@Repository
public interface CustomerRepository extends ResourceRepository<Customer, String> {
}

资源库.java

@NoRepositoryBean
public interface ResourceRepository<T, I> extends MongoRepository<T, I> {

    Page<T> findAll(Query query, Pageable pageable);
}

资源储存库实作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);
    }
}

客户服务.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

62lalag4

62lalag43#

我已经使用了带有$skip和$limit的Aggregation查询,它工作得很好,当你需要对一个复杂的查询结果进行分页时,它非常有用。对于简单的查询,我使用了spring mongo模板,它接受一个Query对象。Query对象接受一个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/

uqxowvwt

uqxowvwt4#

另一种(可能更简单)限制查询结果的方法是在使用MongoRepository时在方法声明中添加过滤器。关键字 topfirst 都可以用来达到这个目标,同时指定所需结果的数量(或者省略它,这样只获得一个结果)。
下面的代码是一个示例,可在 docs.spring.ioMongoRepositories的 * www.example.com * 文档中找到(下面的链接)。

User findFirstByOrderByLastnameAsc();

User findTopByOrderByAgeDesc();

Page<User> queryFirst10ByLastname(String lastname, Pageable pageable);

Slice<User> findTop3ByLastname(String lastname, Pageable pageable);

List<User> findFirst10ByLastname(String lastname, Sort sort);

List<User> findTop10ByLastname(String lastname, Pageable pageable);

您还可以对查询应用分页(文档中提供了更多详细信息)。

关于排序的一些额外信息:

由于其他的回答也对排序有一些见解,我想在这方面提出其他的选择。

如果您的方法总是以相同的方式对结果进行排序,则可以通过在方法声明中使用 OrderBy 关键字进行排序,然后根据您的用例后跟 AscDesc

List<User> findFirst10ByLastnameOrderByAgeAsc(String lastname);

List<User> findFirst10ByLastnameOrderByAgeDesc(String lastname);

如果要动态排序结果,可以在方法上使用 Sort 参数并提供。

List<User> findFirst10ByLastname(String lastname, Sort sort);

例如,在方法调用中提供 Sort.by(DESC,“age”) 将定义 { age:-1 } 作为查询的排序。

参考资料

https://docs.spring.io/spring-data/mongodb/docs/3.2.10/reference/html/#repositories.query-methods

相关问题