Hippo Site Toolkit Query interface and pagination
Today an interesting question came from a developer of one of our implementation partners. He wanted to list items from our JCR repository and use pagination. In this post I tried to make a summary out of the conversation.
The query was:
HstQuery query = getQueryManager().createQuery(requestContext, scope, filterBean); Filter filter = query.createFilter(); filter.addContains(".", "my keywords"); query.setFilter(filter); HstQuery queryResult = query.execute();
The developer tried to get a paged result and the total number of items with:
query.setOffset(0); query.setLimit(10); HippoBeanIterator hits = queryResult.getHippoBeans(); hits.getSize();
The result contained indeed 10 items but hits.getSize(); also returned 10. What’s going wrong? Ard Schrijvers explained:
If you use setLimit(3), you will get at most 3 hits, but never more. getSize() from the queryResult returns at most 3. Even if the search criteria matched hundreds of documents. If you use offset(10) and no limit, getSize() returns just 10 hits less then without the offset.
This limit is there to be used for performance, and suits for example very well “show last 3 agenda items on homepage”.
If you need paging and only want 10 results, do not use setLimit(int limit).
What you do use, is just the query without setLimit(). Then you’ll get back a queryResult, from which you get a HippoBeanIterator. This is a normal Iterator, with some extensions. A very important one is the method skip(int skipNum).
From the HippoBeanIterator, you can simply iterate the beans you need. Make sure you use skip(int skipNum) to jump to the correct place. If the current page is 11 and pagesize is 20, set skipNum to 220.
Then fill your List in a for loop from skipNum — skipNum + pageSize.
What about performance?
The skip is propagated to the JCR NodeIterator. If you want to display item 100-110, and you use skip(100), still only 10 Beans will be created. JCR nodes for Beans 0-99 are not fetched.
What if you need the total number of hits?
Use getSize(). The getSize() on the the HstQueryResultImpl or on the HippoBeanIteratorImpl does not actually populate the entire iterator with HippoBeans. It is a call through the JCR NodeIterator, which in JackRabbit is some lazy loading iterator, and, where the getSize is propagated to the executed query, without fetching actual nodes.