There are many ways to implement pagination for AEM content. Effectively choosing the right solution will indeed Bu decrease development time, and promote a performant experience to your end users. AEM has multiple search API’s like xPath, JCR SQL2, Node JCR, Query Builder, etc… But in my opinion, the Query Builder API would be the most effective decision when building a solution with pagination. In AEM, the Query Builder API has emerged as the preferred solution for creating pagination experiences. In this article, we will explore why the Query Builder API stands out as the go-to choice for pagination in AEM.
1. Understanding Pagination in AEM
What is pagination? In general, pagination is a process that divides large sets of content into smaller, more manageable sections, commonly referred to as “pages”; but however, with AEM, anything can be paginated. By doing so, users can navigate through content easily, without being presented with an exhaustive list all at once. In AEM, pagination is particularly crucial for content-heavy websites or applications, ensuring that visitors can access desired information quickly. You can probably imagine, when the page first loads, you can see the first 10 results, and clicking on “next”, you are able to see the next 10 results, and so on…
2. The Query Builder API: An Overview
The Query Builder API is a powerful tool within AEM that allows developers to construct complex queries to retrieve content from the AEM repository. It is designed to provide a more flexible and efficient way of searching and fetching content than traditional JCR-SQL2 queries. The Query Builder API abstracts the underlying technology and provides an easy-to-use interface to interact with the AEM repository.
3. Benefits of the Query Builder API for Pagination
3a. Performance Optimization
One of the primary reasons the Query Builder API is preferred for pagination in AEM is its ability to optimize performance. When dealing with large repositories, traditional queries can be resource-intensive and slow, impacting the page loading time and user experience. The Query Builder API, on the other hand, leverages optimized query execution, resulting in faster response times and enhanced page performance.
3b. Flexibility and Customization
The Query Builder API offers developers a wide range of parameters and options to fine-tune their queries. This level of flexibility enables developers to customize the pagination logic based on specific use cases. Whether it’s setting the number of items per page, defining sorting criteria, or filtering results, the Query Builder API empowers developers to tailor pagination experiences according to project requirements.
3c. Support for Dynamic Content
In dynamic environments where content changes frequently, pagination needs to adapt to reflect these updates accurately. The Query Builder API can seamlessly handle dynamic content by providing real-time results based on the most recent data in the AEM repository. This ensures that the user always receives the latest content, maintaining an up-to-date and engaging user experience.
3d. Facilitating Search Functionality
Pagination is often used in conjunction with search functionality to improve content discovery. The Query Builder API’s capability to perform complex searches across various content attributes makes it a natural fit for integrating search with pagination. By combining these features, users can easily find and navigate to the exact content they need.
4. Pagination and More Features with Query Builder API
4a. Offset and Limit
The Query Builder API allows developers to define the starting point (offset) and the maximum number of items (limit) to fetch for each page. This enables seamless navigation between pages, allowing users to access content beyond the first page of results.
4b. Sorting
To enhance user experience, pagination often goes hand in hand with sorting. The Query Builder API allows developers to specify sorting criteria based on content attributes. For example, you can sort content by date, popularity, or any other relevant property to ensure a logical order for the paginated results.
4c. Search Filters
Incorporating search filters along with pagination empowers users to refine their search queries and find specific content efficiently. The Query Builder API enables developers to apply various filters and constraints to narrow down the results, creating a more personalized experience for users.
4d. Query Aggregation
The Query Builder API also supports query aggregation, which enables developers to group results based on specific attributes. This feature is particularly useful when presenting aggregated data, such as categories or tags, in a paginated manner.
4e. Content Pre-fetching
To further optimize user experience, the Query Builder API allows developers to implement content pre-fetching. By fetching additional content in the background, users experience faster loading times when navigating between pages, reducing any perceived delays.
5. A Simple Servlet for Querying Pages in Java
Below is an example of a simple Java servlet that uses the Query Builder API to query pages from the AEM repository for pagination purposes:
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 | import org.apache.sling.api.SlingHttpServletRequest; import org.apache.sling.api.SlingHttpServletResponse; import org.apache.sling.api.servlets.SlingAllMethodsServlet; import org.osgi.service.component.annotations.Component; import org.osgi.service.component.propertytypes.ServiceRanking; import org.osgi.service.component.annotations.Reference; import com.day.cq.search.PredicateGroup; import com.day.cq.search.Query; import com.day.cq.search.QueryBuilder; import com.day.cq.search.result.SearchResult; import java.io.IOException; import java.util.HashMap; import java.util.Map; import javax.servlet.Servlet; import javax.servlet.ServletException; @Component(service = Servlet.class, property = { "sling.servlet.methods=GET", "sling.servlet.paths=/bin/findPagePaths", "sling.servlet.extensions=json" }) @ServiceRanking(-1001) // Adjust the service ranking as per your requirement public class PaginatedPagesServlet extends SlingAllMethodsServlet { private static final long serialVersionUID = 1L; @Reference private QueryBuilder queryBuilder; @Override protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) throws ServletException, IOException { // Get request parameters for search and pagination String searchTerm = request.getParameter("q"); int currentPage = Integer.parseInt(request.getParameter("page")); int pageSize = 10; // Number of items per page // Calculate the offset to start retrieving items int offset = (currentPage - 1) * pageSize; // Build the query map for the QueryBuilder API Map<String, String> queryMap = new HashMap<>(); queryMap.put("path", "/content"); // Replace with your desired root path queryMap.put("type", "cq:Page"); queryMap.put("fulltext.relPath", "jcr:content"); queryMap.put("fulltext", searchTerm); // Use the "q" parameter for search terms queryMap.put("p.offset", String.valueOf(offset)); queryMap.put("p.limit", String.valueOf(pageSize)); // Execute the query Query query = queryBuilder.createQuery(PredicateGroup.create(queryMap), request.getResourceResolver().adaptTo(Session.class)); SearchResult result = query.getResult(); // Get the paths of the pages from the search result using GJSON JSONArray pathsArray = new JSONArray(); result.getHits().forEach(hit -> { String path = hit.getResource().getPath(); pathsArray.add(path); }); // Send the paginated content (paths of the pages) to the response response.setContentType("application/json"); response.getWriter().write(pathsArray.toJSONString()); } } |
Curl
1 2 3 4 5 6 7 8 9 | # Replace "http://your_server" with the base URL of your AEM instance. # Replace "/bin/findPagePaths?q=search_term&page=1" with the path to your servlet, # the desired search term (search_term), and the desired page number. # Search with "your_search_term" and get results for Page 1 curl -X GET "http://your_server/bin/findPagePaths?q=your_search_term&page=1" # Search with "another_search_term" and get results for Page 2 curl -X GET "http://your_server/bin/findPagePaths?q=another_search_term&page=2" |
5. Conclusion
In conclusion, the Query Builder API in Adobe Experience Manager is a versatile and powerful tool that provides an ideal solution for implementing pagination experiences. With its performance optimization, flexibility, and support for dynamic content, the Query Builder API ensures that users can navigate through content-rich websites or applications seamlessly.
By incorporating features like offset and limit, sorting, search filters, query aggregation, and content pre-fetching, developers can create highly customizable and efficient pagination experiences for their AEM projects. Additionally, the provided Java servlet example demonstrates how the Query Builder API can be used to retrieve paginated content from the AEM repository. As AEM continues to evolve, leveraging the Query Builder API will remain essential for maintaining an excellent user experience and keeping users engaged with your content.