使用 mongoTemplate 进行分页

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

我有一个可分页查询:

Query query = new Query().with(new PageRequests(page, size))

如何使用 MongoTemplate 执行它?我没有看到任何方法返回

Page<T>

java spring-data spring-data-mongodb
8个回答
85
投票

确实,

MongoTemplate
没有
findXXX
与 Pageables。

但是您可以使用 Spring 存储库

PageableExecutionUtils
来实现这一点。

在您的示例中,它看起来像这样:

Pageable pageable = new PageRequests(page, size);
Query query = new Query().with(pageable);
List<XXX> list = mongoTemplate.find(query, XXX.class);
return PageableExecutionUtils.getPage(
                       list, 
                       pageable, 
                       () -> mongoTemplate.count(Query.of(query).limit(-1).skip(-1), XXX.class));

就像在原来的 Spring Data Repository 中一样,

PageableExecutionUtils
将执行计数请求并将其包装成一个不错的
Page

在这里你可以看到spring也在做同样的事情。


22
投票

基于 d0x 的答案并查看 spring 代码。我正在使用这个变体,它可以解决 spring-boot-starter-data-mongodb 依赖关系,而不需要添加 spring data commons。

@Autowired
private MongoOperations mongoOperations;

@Override
public Page<YourObjectType> searchCustom(Pageable pageable) {
    Query query = new Query().with(pageable);
    // Build your query here

    List<YourObjectType> list = mongoOperations.find(query, YourObjectType.class);
    long count = mongoOperations.count(query, YourObjectType.class);
    Page<YourObjectType> resultPage = new PageImpl<YourObjectType>(list , pageable, count);
    return resultPage;
}

19
投票

MongoTemplate
没有返回
Page
的方法。
find()
方法返回普通的
List

with(new PageRequests(page, size)
在内部用于通过 MongoDB 查询调整
skip
limit
(我认为是通过计数查询进行的)

Page
可以与MongoDB存储库结合使用,这是Spring数据存储库的一个特例。

因此,您必须使用

MongoRepository
Page findAll(Pageable pageable)
来获取分页结果(实际上继承自
PagingAndSortingRepository
)。


4
投票

到目前为止,所有答案都执行查询两次。这通常不是您想要的。这是一个使用聚合仅运行一次的解决方案。

public class Result<T> {
    int totalCount;
    List<T> objects;
}

public <T, R extends Result<T>> R executePaged(Class<T> inputType,
                                               Criteria criteria,
                                               Pageable pageable,
                                               Class<R> resultType) {
    var match = Aggregation.match(criteria);
    var facets = Aggregation
            .facet(
                    Aggregation.sort(pageable.getSort()),
                    Aggregation.skip(pageable.getOffset()),
                    Aggregation.limit(pageable.getPageSize())
            ).as("objects")
            .and(
                    Aggregation.count().as("count")
            ).as("countFacet");
    var project = Aggregation
            .project("objects")
            .and("$countFacet.count").arrayElementAt(0).as("totalCount");

    var aggregation = Aggregation.newAggregation(match, facets, project);
    return mongoTemplate.aggregate(aggregation, inputType, resultType)
            .getUniqueMappedResult();
}

备注:

  • 扩展并参数化
    Result<T>
    以作为
    resultType
    传递,否则反序列化器不知道要使用什么类
  • pageable
    必须使用
    Sort
  • 创建
  • 如果需要,您仍然可以随后创建
    PageImpl

示例:

class Person {
    String name;
    Date birthdate;
}

class PersonResult extends Result<Person>{}

PersonResult result = executePaged(Person.class,
      Criteria.where("name").is("John"),
      PageRequest.of(3, 50).withSort(Sort.by("birthdate")),
      PersonResult.class);

System.out.println("Total #Johns: " + result.totalCount);
System.out.println("Johns on this page: " + result.objects);

3
投票

默认情况下,spring mongo template没有按页面查找的方法。它搜索并返回整个记录列表。我试过这个,它有效:

Pageable pageable = new PageRequests(0, 10);                              
Query query = new Query(criteria); 
query.with(pageable);   
List<User> lusers = mt.find(query, User.class);   
Page<User> pu = new PageImpl<>(lusers, pageable, mongoTemplate.count(newQuery(criteria), User.class));

1
投票

此处提供的解决方案均不适用于我自己的情况。 我尝试使用下面的中等帖子中的解决方案,它从未返回分页结果,但返回所有结果,这不是我所期望的

return PageableExecutionUtils.getPage(
        mongoTemplate.find(query, ClassName.class),
        pageable,
        () -> mongoTemplate.count(query.skip(0).limit(0), ClassName.class)
);

所以我找到了一种更好的方法来解决这个问题,并且它对我的情况有效:

return PageableExecutionUtils.getPage(
            mongoTemplate.find(query.with(pageable), ClassName.class),
            pageable,
            () -> mongoTemplate.count(query, ClassName.class));

0
投票

要使用

Query
执行
Pageable
MongoTemplate
,您可以使用
find(Query, Class, String)
方法,然后将结果转换为
Page
。具体方法如下:

public Page<YourEntity> executeQuery(Query query, Pageable pageable) {
    long totalCount = mongoTemplate.count(query, YourEntity.class);
    query.with(pageable);
    List<YourEntity> resultList = mongoTemplate.find(query, YourEntity.class);
    return PageableExecutionUtils.getPage(resultList, pageable, () -> totalCount);
}

-1
投票
return type Mono<Page<Myobject>>...

return this.myobjectRepository.count()
        .flatMap(ptiCount -> {
          return this.myobjectRepository.findAll(pageable.getSort())
            .buffer(pageable.getPageSize(),(pageable.getPageNumber() + 1))
            .elementAt(pageable.getPageNumber(), new ArrayList<>())
            .map(ptis -> new PageImpl<Myobject>(ptis, pageable, ptiCount));
        });
© www.soinside.com 2019 - 2024. All rights reserved.