2018-12-19

Tags: JCR, XPATH, HippoCMS

Summary:

When I was developing on CQ5/AEM6, querying via SQL2 felt more natural to me (having worked in databases & data-warehouses). In a different job (using HippoCMS/Bloomreach DXP), I was forced to learn XPath queries because SQL2 was not supported. Since SQL2 queries eventually get converted to XPath, this was a useful language to learn.

This reference breaks queries into:

  1. Path Constraints

  2. Property Constraints

  3. Sorting Results

  4. Hippo Query Hints

  5. Appendix: JCR XPath Functions

  6. Appendix: Bean Example

Examples should work on the Hippo CMS "Go Green" example project. If running locally, they can be tested at http://localhost:8080/cms/repository/

Path Constraints

The first concept to understand is finding nodes by path constraints (called expressions):

  • / direct descendent node

  • // any descendent

  • * any node name (can’t be used with a partial node name for pattern matching)

Some examples of path constraints are:

Property Constraints

The most commonly desired query is finding JCR nodes by a property value.

Sorting Results

Append order by @PROP_NAME with optional descending or ascending (default, so no need to add) at the end of the query. Abbreviations will be ignored. JCR queries also ignore unrecognized/missing properties. Multiple properties can be combined in more complex sorting, such as //content//*[@gogreen:source] | @gogreen:date | @gogreen:title order by @gogreen:title descending, @gogreen:date ascending

Hippo Query Hints

Folder names are used for filtering more than for efficiency. Hippo’s query speed is optimized by leveraging jcr:uuid. The property hippo:paths is a multiple value property with jcr:uuid of current node, then each of its ancestors, then the root node last (whose jcr:uuid=cafebabe-cafe-babe-cafe-babecafebabe). Hippo CMS therefore filters descendendants of a folder by including hippo:path=$FOLDER_UUID.

The /cms/repository query UI provides several interesting features:

  • Query Results table includes columns jcr:primaryType, jcr:path, jcr:score by default

  • If querying with the element(*, docType) function is used, the table adds columns for required properties (only directly on the node)

  • Can manually force display of other properties in the query results table by appending | @propName before sorting clauses, i.e. //element(*, gogreen:newsdocument) | @gogreen:documenttype |@gogreen:location order by @gogreen:location.

    • this is limited to properties on the query result node (not properties on parent or child nodes)

Tip
Get it right first, then get it fast.
Tip
The order of constraints can matter - place more restrictive ones first
Tip
Debug Java queries by logging the actual query used, then run the logged query through the /cms/respository UI

Appendix: JCR XPath Functions

  • element(*, docType) nodes of type docType or inherited types

  • jcr:like(propName, pattern) pattern matching

  • jcr:contains(propName, text) text search

  • jcr:score() sorting

  • type matching functions xs:string, xs:base64Binary, xs:double, xs:long, xs:boolean, xs:dateTime, xs:IDREF

    • dateTime formats MUST be `yyyy-MM-D’T';HH:mm:ss.000Z (ie property >=xs:dateTime('2018-02-01T00:00:00.000Z'))

Appendix: Bean Example

Example from helper classes from a Bean
//*[
  (@hippo:paths='0dd35126-de28-4948-b43d-3949e9b1f5bb') and
  (@hippo:availability='live') and
  not(@jcr:primaryType='nt:frozenNode') and
  ((@jcr:primaryType='gogreen:newsdocument')) and
  ./gogreen:image/@hippo:docbase='7aeca376-1e1b-4c5d-90cf-fe497f6bcde6'
] order by @hippostdpubwf:lastModificationDate descending`
  • Could be manually simplified, such as removing some unnecessary parenthesis

  • Notice the use of UUIDs for the @hippo:paths (from site content folder), @hippo:docbase. These are performance optimizations.

  • The UUIDs are unlikely to match any of your instances (so are only useful within a cluster).