1 HstQuery bootstrapping - BloomReach Experience - Open Source CMS

This article covers a Hippo CMS version 10. There's an updated version available that covers our most recent release.

31-10-2016

1 HstQuery bootstrapping

Getting hold of a HstQueryManager

The HstQueryManager can be retrieved from the current request context.

  1. In a HstComponent

    HstComponent extending BaseHstComponent:

    public class LatestItems extends BaseComponent {  @Override
        public void doBeforeRender(HstRequest request, HstResponse response) {
            final HstRequestContext context = request.getRequestContext();
            final HstQueryManager hstQueryManager = context.getQueryManager();
    
            [...]
        }
    }
  2. In a JAXRS Service Resource extending from org.hippoecm.hst.jaxrs.services.AbstractResource

    ProductPlainResource extending AbstractResource:

    @Path("/products/")
    public class ProductPlainResource extends AbstractResource {
        @GET
        @Path("/{productType}/")
        public List<ProductRepresentation> getProductResources(....) {
            final HstRequestContext requestContext = RequestContextProvider.get();
            final HstQueryManager hstQueryManager = context.getQueryManager();
    
            [...]
        }
    }

In cases where you don't have a HstRequestContext (for example for during some background process or for external application integration that does not involve a http request), you can get hold of the HstQueryManager to create an HstQuery directly through the Spring Component Manager:

Repository repo = HstServices.getComponentManager().getComponent(Repository.class.getName());
Credentials creds = HstServices.getComponentManager().getComponent(Credentials.class.getName() + ".default");
ContentBeansTool cbt = HstServices.getComponentManager().getComponent(ContentBeansTool.class.getName());

Session session = null;
try {
    session = repo.login(creds);
    HstQueryManager queryManager = cbt.createQueryManager(session);
} finally {
    if (session != null) session.logout();
}

Creating a new HstQuery

Once you have the HstQueryManager, there are multiple ways to create a new HstQuery. Below, we explain the usual way to do this. Other ways are very similar, also see the Javadocs from org.hippoecm.hst.content.beans.query.HstQueryManager.

HstQueryManager#createQuery:

/**
* Creates a query, with scope HippoBean and Filter for types of filterBean. If
* includeSubTypes is <code>true</code>, the result may also contain
* HippoBean's whose primarytype is a subtype of the filterBean type.
*
* @param scope
* @param filterBean
* @param includeSubTypes
* @return a new <code>{@link HstQuery}</code> with scope & filter
* @throws QueryException
*/
HstQuery createQuery(HippoBean scope, Class<? extends HippoBean> filterBean,
                     boolean includeSubTypes) throws QueryException;

In the code above the createQuery method takes three arguments:

  1. HippoBean scope : The scope to search below in the repository. A HippoBean is backed by a JCR Node, which represents a location in the content tree of the repository. The scope identifies the sub-tree in the repository for searching documents. Note that instead of argument HippoBean, there are also methods in the HstQueryManager that directly take the JCR Node as scope, for example HstQuery createQuery(Node node, Class<? extends HippoBean> filterBean, boolean includeSubTypes);

  2. Class<? extends HippoBean> filterBean : This is a filter for the possible hits. Only hits of type filterBean will be part of the result. Depending on the last argument, includeSubTypes, also subtypes are inluded in the result.

  3. includeSubTypes : when true, also subtypes of the filterBean can be part of the result.

Here's an example code snippet for creating a new HstQuery in an  HstComponent extending from BaseHstComponent:

HippoBean scope = request.getRequestContext().getSiteContentBaseBean();
try {
    // create the query to search below 'scope', return beans that are of type
    // BaseDocument bean or a subclass/sub-jcr-types
    HstQuery hstQuery = request.getRequestContext().getQueryManager().createQuery(scope, BaseDocument.class, true);

    [...]
} catch (QueryException e) {
    throw new HstComponentException("Exception occured during creation of HstQuery.", e);
}

Setting a limit and offset

In general it is always best to set a limit. If you do not specify a limit, the HST by default will set a limit of 1000. The best way is to set the limit equal to the number of items you want to show, for example pageSize. If you combine this with offset, you can easily always fetch the correct items.

For example, if pageSize = 10, and you want to show the 3rd page ( currentPage = 3), use:

hstQuery.setLimit(pageSize);
hstQuery.setOffset(pageSize * (currentPage - 1));

Now, there is one more catch. If you have set a limit of, say, 10, then, HstQueryResult#getSize() will return at most 10. So, what if you need to know how many pages there are? For this, you can use getTotalSize(). This method returns the total number of hits.

Always set a limit, preferably to just the number you need to show

If you don't set a limit, HST sets a limit of 1000 for safety. This is already large, and might result in slower searches. For optimal performance, set a limit (and optionally an offset).

Sorted results

The HstQuery can "order by" / "sort by" multiple properties, ascending or descending. The sorting is done according to the order in which the properties to sort on are added. Sorting can only be done on properties (meta-data) which are directly stored on the document. Properties which are part of a Compound in a document can not be used for sorting.

For example:

Sorting / Ordering:

// first sort the results on the "example:date" descending (newest first)
hstQuery.addOrderByDescending("example:date");

// if there are hits with the same "example:date", we then sort ascending by
// "example:title"
hstQuery.addOrderByAscending("example:title");

// if there are hits with the same date and title, we sort descending by
// "hippostdpubwf:publicationDate"
hstQuery.addOrderByDescending("hippostdpubwf:publicationDate");

// etc

Sorting can only be done on properties directly on the documents

Also see Sorting search results in a query can only be done on direct properties of Documents

Including or excluding extra scopes

An HstQuery can search in multiple scopes, and also, some scopes can be excluded. This can be done by addScope and excludeScope :

Including extra or excluding scopes:

/**
 * add scopes to search in.
 * If the exact scope is already added to exclude from the search, it is
 * removed from the excluded list.
 * @param scopes
 */
void addScopes(List<HippoBean> scopes);

/**
 * add scopes to search in.
 * If the exact scope is already added to exclude from the search, it is
 * removed from the excluded list.
 * @param scopes
 */
void addScopes(Node[] scopes);

/**
 * add scopes to exclude from search.
 * If the exact scope is already added as a scope to search in, it is
 * removed from there
 * @param scopes
 */
void excludeScopes(List<HippoBean> scopes);

/**
 * add scopes to exclude from search.
 * If the exact scope is already added as a scope to search in, it is
 * removed from there
 * @param scopes
 */
void excludeScopes(Node[] scopes);

Assuming that I want to search through the entire content of the current site and through the assets I can use something like:

HippoBean siteScope = getSiteContentBaseBean(request);
// because we will also search in assets, make sure the filter is not project
// specific but HippoDocument.class or if you do not want to use
// HippoDocument.class ,set explicitly all bean classes you want to search for
HstQuery hstQuery = queryManager.createQuery(siteScope, HippoDocument.class, true);

// extra scopes to search in
List<HippoBean> extraScopes = new ArrayList<HippoBean>();
// also search in assets
extraScopes.add(getAssetBaseBean(request));
hstQuery.addScopes(extraScopes);

// scopes to exclude, for example 'comments'
List<HippoBean> excludeScopes = new ArrayList<HippoBean>();
HippoBean commentsScope = siteScope.getBean("comments",
                                             HippoFolderBean.class);
excludeScopes.add(commentsScope);
hstQuery.excludeScopes(excludeScopes);
Did you find this page helpful?
How could this documentation serve you better?
On this page
    Did you find this page helpful?
    How could this documentation serve you better?