Find all AEM Pages with Specific Page Properties with Query Builder API

The Query Builder is a great tool that allows us to search for nodes in the JCR. We often as AEM developers use this tool to build a query for us to use in the backend to build query descriptions (predicates); the set of predicates produced will call the Predicate Evaluator which knows how to handle that specific predicate for XPath, filtering, and facet extraction.

In this article, we will be sharing query examples to find all AEM pages with specific page page properties using the Query Builder Debugger tool.


1. Find all AEM pages with a single page property

Find all pages under /content/we-retail,
and has page properties set with cq:productMaster == ‘/var/commerce/products/we-retail/wo/pants/faba_running_pants’
show max results.

1
2
3
4
5
6
path=/content/we-retail
type=cq:Page
property=jcr:content/cq:productMaster
property.value=
/var/commerce/products/we-retail/wo/pants/faba_running_pants
p.limit=-1

http://localhost:4502/libs/cq/search/content/querydebug.html?_charset_=UTF-8&query=path%3D%2Fcontent%2Fwe-retail%0D%0Atype%3Dcq%3APage%0D%0Aproperty%3Djcr%3Acontent%2Fcq%3AproductMaster%0D%0Aproperty.value%3D%09%0D%0A%2Fvar%2Fcommerce%2Fproducts%2Fwe-retail%2Fwo%2Fpants%2Ffaba_running_pants%0D%0Ap.limit%3D-1

Example Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.servlets.SlingAllMethodsServlet;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceResolverFactory;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;

import com.day.cq.search.QueryBuilder;
import com.day.cq.search.result.SearchResult;
import com.day.cq.search.result.Hit;
import com.day.cq.search.Query;

import org.json.JSONArray;
import org.json.JSONObject;

import javax.servlet.Servlet;
import java.io.IOException;
import java.util.Collections;
import java.util.Map;

@Component(
    service = Servlet.class,
    property = {
        "sling.servlet.paths=/bin/queryservlet",
        "sling.servlet.methods=GET"
    }
)
public class QueryServlet extends SlingAllMethodsServlet {

    @Reference
    private ResourceResolverFactory resolverFactory;

    @Reference
    private QueryBuilder queryBuilder;

    @Override
    protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) throws IOException {
        response.setContentType("application/json");
        response.setCharacterEncoding("UTF-8");

        final Map<String, Object> authInfo = Collections.singletonMap(
            ResourceResolverFactory.SUBSERVICE,
            "sourcedCodeSystemUser");

        try (ResourceResolver resourceResolver = resolverFactory.getServiceResourceResolver(authInfo)) {
            String queryPath = "/content/we-retail";
            String queryType = "cq:Page";
            String queryProperty = "jcr:content/cq:productMaster";
            String queryPropertyValue = "/var/commerce/products/we-retail/wo/pants/faba_running_pants";

            Map<String, String> queryParams = new HashMap<>();
            queryParams.put("path", queryPath);
            queryParams.put("type", queryType);
            queryParams.put("property", queryProperty);
            queryParams.put("property.value", queryPropertyValue);

            Query query = queryBuilder.createQuery(PredicateGroup.create(queryParams), resourceResolver.adaptTo(javax.jcr.Session.class));
            SearchResult result = query.getResult();

            JSONArray resultsArray = new JSONArray();

            for (Hit hit : result.getHits()) {
                Resource resource = hit.getResource();
                JSONObject pageData = new JSONObject();
                pageData.put("path", resource.getPath());
                resultsArray.put(pageData);
            }

            JSONObject jsonResponse = new JSONObject();
            jsonResponse.put("results", resultsArray);
            response.getWriter().write(jsonResponse.toString());
        } catch (Exception e) {
            JSONObject errorResponse = new JSONObject();
            errorResponse.put("error", "An error occurred while processing the request.");
            response.getWriter().write(errorResponse.toString());
        }
    }
}

Curl Example

1
curl -X GET http://localhost:4502/bin/queryservlet

Output

1
2
3
4
5
6
7
8
9
10
11
{
  "results": [
    {
      "path": "/content/we-retail/en"
    },
    {
      "path": "/content/we-retail/de"
    }
    // ... more paths
  ]
}

2. Find all AEM pages with multiple page properties

Find all pages under /content/we-retail,
and has page properties set with cq:productMaster == ‘/var/commerce/products/we-retail/wo/pants/faba_running_pants’
and has page properties set with cq:template == ‘/conf/we-retail/settings/wcm/templates/product-page’
show max results.

1
2
3
4
5
6
7
8
9
10
11
path=/content/we-retail
type=cq:Page
path=/content/we-retail
type=cq:Page
group.1_property=jcr:content/cq:productMaster
group.1_property.value=
/var/commerce/products/we-retail/wo/pants/faba_running_pants
group.2_property=jcr:content/cq:template
group.2_property.value=
/conf/we-retail/settings/wcm/templates/product-page
p.limit=-1

http://localhost:4502/libs/cq/search/content/querydebug.html?_charset_=UTF-8&query=path%3D%2Fcontent%2Fwe-retail%0D%0Atype%3Dcq%3APage%0D%0Agroup.1_property%3Djcr%3Acontent%2Fcq%3AproductMaster%0D%0Agroup.1_property.value%3D%09%0D%0A%2Fvar%2Fcommerce%2Fproducts%2Fwe-retail%2Fwo%2Fpants%2Ffaba_running_pants%0D%0Agroup.2_property%3Djcr%3Acontent%2Fcq%3Atemplate%0D%0Agroup.2_property.value%3D%09%0D%0A%2Fconf%2Fwe-retail%2Fsettings%2Fwcm%2Ftemplates%2Fproduct-page%0D%0Ap.limit%3D-1

Example Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.servlets.SlingAllMethodsServlet;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceResolverFactory;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;

import com.day.cq.search.QueryBuilder;
import com.day.cq.search.result.SearchResult;
import com.day.cq.search.result.Hit;
import com.day.cq.search.Query;

import org.json.JSONArray;
import org.json.JSONObject;

import javax.servlet.Servlet;
import java.io.IOException;
import java.util.Collections;
import java.util.Map;

@Component(
    service = Servlet.class,
    property = {
        "sling.servlet.paths=/bin/queryservlet",
        "sling.servlet.methods=GET"
    }
)
public class QueryServlet extends SlingAllMethodsServlet {

    @Reference
    private ResourceResolverFactory resolverFactory;

    @Reference
    private QueryBuilder queryBuilder;

    @Override
    protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) throws IOException {
        response.setContentType("application/json");
        response.setCharacterEncoding("UTF-8");

        final Map<String, Object> authInfo = Collections.singletonMap(
            ResourceResolverFactory.SUBSERVICE,
            "sourcedCodeSystemUser");

        try (ResourceResolver resourceResolver = resolverFactory.getServiceResourceResolver(authInfo)) {
            Map<String, String> queryParams = new HashMap<>();
            queryParams.put("path", "/content/we-retail");
            queryParams.put("type", "cq:Page");
            queryParams.put("group.1_property", "jcr:content/cq:productMaster");
            queryParams.put("group.1_property.value", "/var/commerce/products/we-retail/wo/pants/faba_running_pants");
            queryParams.put("group.2_property", "jcr:content/cq:template");
            queryParams.put("group.2_property.value", "/conf/we-retail/settings/wcm/templates/product-page");
            queryParams.put("p.limit", "-1");

            Query query = queryBuilder.createQuery(PredicateGroup.create(queryParams), resourceResolver.adaptTo(javax.jcr.Session.class));
            SearchResult result = query.getResult();

            JSONArray resultsArray = new JSONArray();

            for (Hit hit : result.getHits()) {
                Resource resource = hit.getResource();
                JSONObject pageData = new JSONObject();
                pageData.put("path", resource.getPath());
                resultsArray.put(pageData);
            }

            JSONObject jsonResponse = new JSONObject();
            jsonResponse.put("results", resultsArray);
            response.getWriter().write(jsonResponse.toString());
        } catch (Exception e) {
            JSONObject errorResponse = new JSONObject();
            errorResponse.put("error", "An error occurred while processing the request.");
            response.getWriter().write(errorResponse.toString());
        }
    }
}
For other ways to find AEM pages on AEM using the query builder, checkout this article ->
Find all AEM Pages with Tags with Query Builder API

Was this post helpful?

Hello, I am an enthusiastic Adobe Community Advisor and a seasoned Lead AEM Developer. I am currently serving as an AEM Technical Lead at MNPDigital.ca, bringing over a decade of extensive web engineering experience and more than eight years of practical AEM experience to the table. My goal is to give back to the AEM Full Stack Development community by sharing my wealth of knowledge with others. You can connect with me on LinkedIn.

3 thoughts on “Find all AEM Pages with Specific Page Properties with Query Builder API

Leave a Reply

Your email address will not be published. Required fields are marked *

Back To Top