我有一个可分页查询:
Query query = new Query().with(new PageRequests(page, size))
如何使用 MongoTemplate 执行它?我没有看到任何方法返回
Page<T>
。
确实,
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也在做同样的事情。
基于 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;
}
MongoTemplate
没有返回 Page
的方法。 find()
方法返回普通的 List
。
with(new PageRequests(page, size)
在内部用于通过 MongoDB 查询调整 skip
和 limit
(我认为是通过计数查询进行的)
Page
可以与MongoDB存储库结合使用,这是Spring数据存储库的一个特例。
因此,您必须使用
MongoRepository
的 Page findAll(Pageable pageable)
来获取分页结果(实际上继承自 PagingAndSortingRepository
)。
到目前为止,所有答案都执行查询两次。这通常不是您想要的。这是一个使用聚合仅运行一次的解决方案。
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);
默认情况下,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));
此处提供的解决方案均不适用于我自己的情况。 我尝试使用下面的中等帖子中的解决方案,它从未返回分页结果,但返回所有结果,这不是我所期望的
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));
要使用
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);
}
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));
});