I have a Query with Pageable:
Query query = new Query().with(new PageRequests(page, size))
How can I execute it with MongoTemplate ? I don't see a single method returning Page<T>
.
I have a Query with Pageable:
Query query = new Query().with(new PageRequests(page, size))
How can I execute it with MongoTemplate ? I don't see a single method returning Page<T>
.
It's true that the MongoTemplate
doesn't have findXXX
with Pageables.
But you can use the Spring Repository PageableExecutionUtils
for that.
In your example it would look like this:
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));
Like in the original Spring Data Repository, the PageableExecutionUtils
will do a count request and wrap it into a nice Page
for you.
Here you can see that spring is doing the same.
query.with(Pageable.unpaged())
instead of query.limit(-1).skip(-1)
? –
Incurrence Based on d0x's answer and looking at the spring code. I'm using this variation which works off the spring-boot-starter-data-mongodb dependency without needing to add 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;
}
mongoOperations.count(query.skip(-1).limit(-1), YourObjectType.class)
. Otherwise it will return incorrect count for the query. –
Kerosene MongoTemplate
does not have methods to return Page
. The find()
methods return an ordinary List
.
with(new PageRequests(page, size)
is used internally to adjust skip
and limit
with a MongoDB query (proceeded by a count query I think)
Page
can be used in conjunction with MongoDB repositories which is a specialized case of Spring data repositories.
Thus, you'll have to use MongoRepository
's Page findAll(Pageable pageable)
for paginated results (actually inherited from PagingAndSortingRepository
).
All answers so far are executing the query twice. This is not normally what you want. Here's a solution using aggregations to run it only once.
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();
}
Notes:
Result<T>
to pass as resultType
, otherwise the deserializer doesn't know what class to usepageable
must be created with a Sort
PageImpl
afterwardsExample:
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);
By default, spring mongo template has no method to find by page. It searches, and returns the whole list of records. I Tried this, and It worke:
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));
None of the solutions provided here worked in my own case. I tried using this solution below from a medium post and it has never returned the paged results but returns ALL the results which is not what I am expecting
return PageableExecutionUtils.getPage(
mongoTemplate.find(query, ClassName.class),
pageable,
() -> mongoTemplate.count(query.skip(0).limit(0), ClassName.class)
);
So I found out a better way to go about it and it worked in my case:
return PageableExecutionUtils.getPage(
mongoTemplate.find(query.with(pageable), ClassName.class),
pageable,
() -> mongoTemplate.count(query, ClassName.class));
To execute a Query
with Pageable
using MongoTemplate
, you can use the find(Query, Class, String)
method and then convert the result to a Page
. Here's how you can do it:
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));
});
© 2022 - 2025 — McMap. All rights reserved.