Monday 4 July 2016

AEM QueryBuilder

Here are some examples for using the AEM QueryBuilder.  This took me a bit of time to get used to so it is worth the memory jogger!

Basic Structure

The basic structure uses the AEM adaptTo() to get a QueryBuilder object.

Here the session and builder classes are obtained.  The Query is created with the map of search values (see later).  The SearchResults object would by default be paginated so setting the query.setHitsPerPage(Integer.MAX_VALUE) means we get everything we want.  An iterator is obtained so that we can loop through the results and convert to JSON or further filter if necessary.

    final Session session = request.getResourceResolver().adaptTo(Session.class);
    final QueryBuilder builder = request.getResourceResolver().adaptTo(QueryBuilder.class);
    final Query query = builder.createQuery(PredicateGroup.create(map), session);
    query.setHitsPerPage(Integer.MAX_VALUE);
    final SearchResult result = query.getResult();

    // Iterate over the results
    final Iterator<Resource> resources = result.getResources();



Query Map

The map of values is used to create a PredicateGroup.  This is a group of Predicate objects which are used to match the JCR values against.  The names of the properties will define the predicates that are created for that value.

Create a map to hold the search values.

    final Map<String, Object> map = new HashMap<>();

The 'type' uses the TypePredicate

    map.put("type", "nt:unstructured");

The 'path' uses the PathPredicate

    map.put("path", "/content/mysite/mypages");

The 'boolproperty' defines a JcrBoolPropertyPredicate check. If the search is for 'false' then this is correct if the value is 'false' or not present at all.

    map.put("boolproperty", "live");

    map.put("boolproperty.value", "true");

A numeric range check is possible using the 'rangeproperty'.  This uses the RangePropertyPredicate. There are options for the lower and upper bounds.

    map.put("rangeproperty.property", "age");
    map.put("rangeproperty.lowerBound", age);
    map.put("rangeproperty.lowerOperation", ">=");
Note: even though this is numeric the value provided here should be a string

A number of properties can be matched against.  You can prefix with a #_ to allow multiple properties to be matched on.  These values use a JcrPropertyPredicate

    map.put("1_property", "firstname");
    map.put("1_property.value", "fred");
    map.put("2_property", "surname");
    map.put("2_property.value", "bloggs");

Debugging

Get the Iterator from the PredicateGroup and loop through to see which Predicates have been created for your map.

Always add the values into the map as strings otherwise the predicates don't match.

Use the query debugger to check your map,

    http://localhost:4502/libs/cq/search/content/querydebug.html

No comments:

Post a Comment