CQ newbie
CQ newbie

Reputation: 11

CQ 5 Query builder: to get list of pages without jcr:content node

Using the Query Builder (http://localhost:4502/libs/cq/search/content/querydebug.html), I would want to get a list of pages that do not have a jcr:content child node.

I tried with node, item name etc., but could not find the correct query. Appreciate your help.

    path=/content/products
    type=cq:Page
    node=jcr:content
    node.operation=exists
    node.operation=not
    p.limit=-1

Upvotes: 1

Views: 7659

Answers (1)

Tomek Rękawek
Tomek Rękawek

Reputation: 9304

CQ5 Query Builder transforms provided query into a Jackrabbit XPath query. The latter doesn't support testing the child existence. Following XPath theoretically should work:

/jcr:root/content//element(*, cq:Page)[not(jcr:content)]

but the result is empty. There is a JIRA improvement to add such feature, but it looks abandoned.

So, we have to check it manually. Because CQ predicates doesn't offer such feature (there is no node predicate that you used in your query) we need to write a new predicate:

@Component(metatype = false, factory = "com.day.cq.search.eval.PredicateEvaluator/child")
public class ChildrenPredicateEvaluator extends AbstractPredicateEvaluator {

    public boolean includes(Predicate p, Row row, EvaluationContext context) {
        final Resource resource = context.getResource(row);

        final String name = p.get("name", "");
        final boolean childExists;
        if (name.isEmpty()) {
            childExists = resource.hasChildren();
        } else {
            childExists = resource.getChild(name) != null;
        }

        final String operator = p.get("operator", "exists");
        if ("not_exists".equals(operator)) {
            return !childExists;
        } else {
            return childExists;
        }
    }

    public boolean canXpath(Predicate predicate, EvaluationContext context) {
        return false;
    }

    public boolean canFilter(Predicate predicate, EvaluationContext context) {
        return true;
    }
}

We can use it as follows:

child.name=wantedChild
child.operator=exists

// or

child.name=unwantedChild
child.operator=not_exists

You may also skip the child.name line to check if any children exist / don't exist.

So, your query using this predicate would look like this:

path=/content/products
type=cq:Page
child.name=jcr:content
child.operator=not_exists
p.limit=-1

Upvotes: 3

Related Questions