Reputation: 2072
We have a use case where a user can pass in arbitrary search criteria for a collection, and wants the output paged. Using Spring Data repositories, this is quite simple if we know ahead of time what attributes they may be searching on by simple extending MongoRepository, and declaring a:
Page<Thing> findByFooAndBarAndBaz(Type foo, Type bar, Type baz, Pageable page)
However, if we generate the query ourselves either using the fluent interface or constructing a mongo string and wrapping it in a BasicQuery
class, I can not find a way to get that into a repository instance. There is no:
Page<Thing> findByQuery(Query q, Pageable page)
functionality that I have been able to see.
Nor can I see how to hook into the MongoTemplate
querying functionality with the Page abstraction.
I'm hoping I don't have to roll my own paging (calculating skip and limit parameters, which I guess is not hard) and call into the template directly, but I guess I can if that's the best choice.
Upvotes: 5
Views: 4567
Reputation: 11601
In case you can't express your query within the @Query
-Annotation, you can use the Spring Repository PageableExecutionUtils
for your custom queries.
For example like this:
@Override
public Page<XXX> findSophisticatedXXX(/* params, ... */ @NotNull Pageable pageable) {
Query query = query(
where("...")
// ... sophisticated query ...
).with(pageable);
List<XXX> list = mongoOperations.find(query, XXX.class);
return PageableExecutionUtils.getPage(list, pageable,
() -> mongoOperations.count((Query.of(query).limit(-1).skip(-1), XXX.class));
}
Like in the original Spring Data Repository, the PageableExecutionUtils
will do a separated count
request and wrap it into a nice Page
for you.
Here you can see that spring is doing the same.
Upvotes: 0
Reputation: 83171
You can use the @Query
annotation to execute an arbitrary query through a repository method:
interface PersonRepository extends Repository<Person, Long> {
@Query("{ 'firstname' : ?0 }")
Page<Person> findByCustomQuery(String firstname, Pageable pageable);
}
Generally speaking, @Query
can contain any JSON query you can execute via the shell but with the ?0
kind of syntax to replace parameter values. You can find more information on the basic mechanism in the reference documentation.
Upvotes: 2
Reputation: 2072
I don't think this can be done in the way I'd hoped, but I've come up with a workaround. As background, we put all our methods to do data access in a DAO, and some delegate to the repository, some to the template.
MongoTemplate#count(Query, Class)
Query#with(Pageable)
MongoTemplate#find(Query, Pageable)
List<T>
result from that, the Pageable
that was used for the query and the count
returned from the countQuery run, and construct a new PageImp
to return to the caller.Basically, this (DocDbDomain
is a test domain class for testing out document db stuff):
Query countQuery = new BasicQuery(toMongoQueryString(filterString));
Query pageQuery = countQuery.with(pageRequest);
long total = template.count(countQuery, DocDbDomain.class);
List<DocDbDomain> content = template.find(pageQuery, DocDbDomain.class);
return new PageImpl<DocDbDomain>(content, pageRequest, total);
Upvotes: 4