在MongoRepository中使用limit和skip<Customer,String>

问题描述 投票:0回答:5

我们正在开发一个从 mongoDB 获取数据的项目。我们创建了如下的存储库类

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

我们希望添加跳过/偏移和限制参数作为 findByCustomerId 方法的一部分。其中 limit 用于定义返回的记录数,skip/offset 定义记录数,之后我们需要获取记录。

请帮助我们如何使用 MongoRepository 以最佳方式实现此功能。

mongodb mongodb-query spring-data-mongodb mongorepository
5个回答
12
投票

有两种方法可以做到这一点。

  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. 在查询方法中使用
    Pageable
    参数,并从调用存储库方法的层提供
    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/

动态查询

自定义 Spring 数据存储库实现以及

MongoTemplate
的使用应该有助于实现动态查询。

自定义存储库 - https://docs.spring.io/spring-data/mongodb/docs/3.2.10/reference/html/#repositories.custom-implementations

MongoTemplate
- https://docs.spring.io/spring-data/mongodb/docs/3.2.10/api/org/springframework/data/mongodb/core/MongoTemplate.html


0
投票

一个简单的用例是将自定义存储库与 Query 和 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);
    }
}

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


0
投票

我使用了带有 $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 DB 聚合选项 - https://www.mongodb.com/docs/manual/reference/operator/aggregation/limit/ https://www.mongodb.com/docs/manual/reference/operator/aggregation/skip/


0
投票

限制查询结果的另一种(可能更简单)方法是在使用 MongoRepository 时在方法声明中添加过滤器。关键字 topfirst 都可以用于实现此目标,还指定所需结果的数量(或者通过省略它,从而仅获得一个结果)。

下面的代码是一个示例,可在 MongoRepositoriesdocs.spring.io 文档中找到(链接如下)。

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


0
投票

我没有返回列表,而是尝试使用可选,并且它有效。 在此示例中,如果存在则返回最新记录:

@Repository
public interface IoTTriggerDao extends MongoRepository<IotDECTrigger, String> {

@Query(value = """
    {
       "$and":
       [
          { 'dec._id' : ?0, 'active': false, 'runSingleTime': true },
          { 'processing' : false, 'ended': true}
       ]
    }
    """, sort = "{ 'activeFromDateEpoch' : -1 }")
Optional<IotDECTrigger> getDECSingleTimeFinishedTrigger(String decId);

}

© www.soinside.com 2019 - 2024. All rights reserved.