Expand my Community achievements bar.

Don’t miss the AEM Skill Exchange in SF on Nov 14—hear from industry leaders, learn best practices, and enhance your AEM strategy with practical tips.
SOLVED

using QueryBuilder how to get the absolute URLs of the pages of the components found?

Avatar

Level 9

Using QueryBuilder we can search for component(s) which contain a property with a specific value (e.g. an ID we are looking for).   From this, I need to return some json which includes the properties of the component, the absolute URL of the page this component is on, and the values of some other specific components on the same page, for each hit.  E.g. if we have a bunch of game info pages, each having a game info block component which has gameId as a field, I need to search for specific games (e.g. from a list of previously played game ids), and return the URLS of the game pages found, along with all the main block and other block properties as json so it can be rendered on client side using react.  Below is some code which gets the properties of each game block.

Q1: How to get the absolute URL of the page the block is on or the other components on the page?

Q2: how to improve the search time by narrowing down the predicate?  Eg. how to find published only, and only for the required component type or page template type?

Q3: is there a better way than lots of hand manipulation, e.g. can something like sling model exporters be used?

Q4: I tried to do gson.toJson(searchResult), so I can see what data it holds, but this fails due to duplicate fields.  Is there another way to dump the entire searchResult so we can figure out whats in it, rather than manually printing every value in various loops? I am using eclipse, but haven't seen anything on getting cloud SDK to work in debugger so the vars can be inspected.

 

 

	predicate.put("path", "/content/ourweb/en/");
	predicate.put("type", "cq:component");
	predicate.put("property", "ourId");
	predicate.put("property.value", "1234");
		
	Query query = builder.createQuery(PredicateGroup.create(predicate), session);
	SearchResult searchResult = query.getResult();	
	Gson gson = new GsonBuilder().setPrettyPrinting().create();
	String result = "";
	for(Hit hit : searchResult.getHits()) {
		String path = hit.getPath();		
		result += " hits: " + gson.toJson(hit.getProperties());
	}

 

 

There was a great reply, but it seems to have been deleted.

It had this in it:

            final Resource hitResource = hit.getResource();
if (hitResource != null) {
final Page page = getPage(hitResource);
if (page != null) {
final Resource contentResource = page.getContentResource();
getResultList(resourceResolver, searchResultsLists, hit, hitResource, contentResource);
}

 getPage looks useful, is this a built in function? 

what does page.get|ContentResource() return  exaclty?

1 Accepted Solution

Avatar

Correct answer by
Community Advisor

Hi @TB3dock 

 

Reposting my answers here:

First you can make a VO or POJO class with all the required fields. Let's say I want to keep page title and page link for now. You can add all the fields that you want.

 

public class SearchResultsList {

private String pageTitle;
private String pageLink;

public String getPageTitle() {
return pageTitle;
}

public void setPageTitle(String pageTitle) {
this.pageTitle = pageTitle;
}

public String getPageLink() {
return pageLink;
}

public void setPageLink(String pageLink) {
this.pageLink = pageLink;
}

@Override
public String toString() {
return "SearchResultsList{" +
"pageTitle='" + pageTitle + '\'' +
", pageLink='" + pageLink + '\'' +
'}';
}
}

 

You can create a search service and write the required logic to search here. I am not adding the details here. Predicates and all will go here.

Now call the search service and then get the results.

final SearchResult searchResults = searchService.getSearchResults(resourceResolver, searchRootPath); // whatever you want here can be performed inside the service

 

Once you have the search result preapre the desired result by parsing the raw search result:

 

private List<SearchResultsList> parseResults(SearchResult searchResult, ResourceResolver resourceResolver) {
List<SearchResultsList> searchResultsLists = new ArrayList<>();
totalResult = searchResult.getTotalMatches();
final List<Hit> hits = searchResult.getHits();
try {
for (Hit hit : hits) {
final Resource hitResource = hit.getResource();
if (hitResource != null) {
final Page page = getPage(hitResource);
if (page != null) {
final Resource contentResource = page.getContentResource();
getResultList(resourceResolver, searchResultsLists, hit, hitResource, contentResource);
}
}
}
} catch (RepositoryException e) {
log.error("***** :: parseResult :: Exception *****", e);
}
return searchResultsLists;
}

 

private void getResultList(ResourceResolver resourceResolver, List<SearchResultsList> searchResultsLists, Hit hit, Resource hitResource, Resource contentResource) throws RepositoryException {
if (contentResource != null) {
final ValueMap pageValueMap = contentResource.getValueMap(); // This will give the page property

SearchResultsList searchResultsList = new SearchResultsList();
final String pageTitle = pageValueMap.get(NameConstants.PN_PAGE_TITLE) != null ? pageValueMap.get(NameConstants.PN_PAGE_TITLE).toString() : pageValueMap.get(NameConstants.PN_TITLE).toString();
searchResultsList.setPageTitle(pageTitle);
searchResultsList.setPageLink(StringUtils.isNotBlank(hitResource.getPath()) ? LinksUtil.checkInternalURLByPath(hitResource.getPath(), resourceResolver) : StringUtils.EMPTY); // This will give the page path or link
// rest all can be added here whatever you have in the POJO class.

searchResultsLists.add(searchResultsList);
}
}
private Page getPage(Resource resource) {
if (resource != null) {
ResourceResolver resourceResolver = resource.getResourceResolver();
PageManager pageManager = resourceResolver.adaptTo(PageManager.class);
if (pageManager != null) {
return pageManager.getContainingPage(resource);
}
}
return null;
}

Once you have the list you can convert the list into JSON using Gson and then use it wherever you want.

 

Gson gson = new Gson();
String jsonString = gson.toJson(searchResultsLists); // This will return JSON response of the POJO or VO.

 

View solution in original post

6 Replies

Avatar

Community Advisor

Hi @TB3dock 

 

First you can make a VO or POJO class with all the required fields. Let's say I want to keep page title and page link for now. You can add all the fields that you want.

 

public class SearchResultsList {

private String pageTitle;
private String pageLink;

public String getPageTitle() {
return pageTitle;
}

public void setPageTitle(String pageTitle) {
this.pageTitle = pageTitle;
}

public String getPageLink() {
return pageLink;
}

public void setPageLink(String pageLink) {
this.pageLink = pageLink;
}

@Override
public String toString() {
return "SearchResultsList{" +
"pageTitle='" + pageTitle + '\'' +
", pageLink='" + pageLink + '\'' +
'}';
}
}

 

You can create a search service and write the required logic to search here. I am not adding the details here. Predicates and all will go here.

Now call the search service and then get the results.

final SearchResult searchResults = searchService.getSearchResults(resourceResolver, searchRootPath); // whatever you want here can be performed inside the service

 

Once you have the search result preapre the desired result by parsing the raw search result:

 

private List<SearchResultsList> parseResults(SearchResult searchResult, ResourceResolver resourceResolver) {
List<SearchResultsList> searchResultsLists = new ArrayList<>();
totalResult = searchResult.getTotalMatches();
final List<Hit> hits = searchResult.getHits();
try {
for (Hit hit : hits) {
final Resource hitResource = hit.getResource();
if (hitResource != null) {
final Page page = getPage(hitResource);
if (page != null) {
final Resource contentResource = page.getContentResource();
getResultList(resourceResolver, searchResultsLists, hit, hitResource, contentResource);
}
}
}
} catch (RepositoryException e) {
log.error("***** :: parseResult :: Exception *****", e);
}
return searchResultsLists;
}

 

private void getResultList(ResourceResolver resourceResolver, List<SearchResultsList> searchResultsLists, Hit hit, Resource hitResource, Resource contentResource) throws RepositoryException {
if (contentResource != null) {
final ValueMap pageValueMap = contentResource.getValueMap(); // This will give the page property

SearchResultsList searchResultsList = new SearchResultsList();
final String pageTitle = pageValueMap.get(NameConstants.PN_PAGE_TITLE) != null ? pageValueMap.get(NameConstants.PN_PAGE_TITLE).toString() : pageValueMap.get(NameConstants.PN_TITLE).toString();
searchResultsList.setPageTitle(pageTitle);
searchResultsList.setPageLink(StringUtils.isNotBlank(hitResource.getPath()) ? LinksUtil.checkInternalURLByPath(hitResource.getPath(), resourceResolver) : StringUtils.EMPTY); // This will give the page path or link
// rest all can be added here whatever you have in the POJO class.

searchResultsLists.add(searchResultsList);
}
}

 

Once you have the list you can convert the list into JSON using Gson and then use it wherever you want.

 

Gson gson = new Gson();
String jsonString = gson.toJson(searchResultsLists); // This will return JSON response of the POJO or VO.

 

Hope this helps!

Thanks

Avatar

Level 9

Below is the response from asutosh_jena which seems to have disappeared from this thread.

 

First you can make a VO or POJO class with all the required fields. Let's say I want to keep page title and page link for now. You can add all the fields that you want.

 

public class SearchResultsList {

private String pageTitle;
private String pageLink;

public String getPageTitle() {
return pageTitle;
}

public void setPageTitle(String pageTitle) {
this.pageTitle = pageTitle;
}

public String getPageLink() {
return pageLink;
}

public void setPageLink(String pageLink) {
this.pageLink = pageLink;
}

@Override
public String toString() {
return "SearchResultsList{" +
"pageTitle='" + pageTitle + '\'' +
", pageLink='" + pageLink + '\'' +
'}';
}
}

 

You can create a search service and write the required logic to search here. I am not adding the details here. Predicates and all will go here.

Now call the search service and then get the results.

final SearchResult searchResults = searchService.getSearchResults(resourceResolver, searchRootPath); // whatever you want here can be performed inside the service

 

Once you have the search result preapre the desired result by parsing the raw search result:

 

private List<SearchResultsList> parseResults(SearchResult searchResult, ResourceResolver resourceResolver) {
List<SearchResultsList> searchResultsLists = new ArrayList<>();
totalResult = searchResult.getTotalMatches();
final List<Hit> hits = searchResult.getHits();
try {
for (Hit hit : hits) {
final Resource hitResource = hit.getResource();
if (hitResource != null) {
final Page page = getPage(hitResource);
if (page != null) {
final Resource contentResource = page.getContentResource();
getResultList(resourceResolver, searchResultsLists, hit, hitResource, contentResource);
}
}
}
} catch (RepositoryException e) {
log.error("***** :: parseResult :: Exception *****", e);
}
return searchResultsLists;
}

 

private void getResultList(ResourceResolver resourceResolver, List<SearchResultsList> searchResultsLists, Hit hit, Resource hitResource, Resource contentResource) throws RepositoryException {
if (contentResource != null) {
final ValueMap pageValueMap = contentResource.getValueMap(); // This will give the page property

SearchResultsList searchResultsList = new SearchResultsList();
final String pageTitle = pageValueMap.get(NameConstants.PN_PAGE_TITLE) != null ? pageValueMap.get(NameConstants.PN_PAGE_TITLE).toString() : pageValueMap.get(NameConstants.PN_TITLE).toString();
searchResultsList.setPageTitle(pageTitle);
searchResultsList.setPageLink(StringUtils.isNotBlank(hitResource.getPath()) ? LinksUtil.checkInternalURLByPath(hitResource.getPath(), resourceResolver) : StringUtils.EMPTY); // This will give the page path or link
// rest all can be added here whatever you have in the POJO class.

searchResultsLists.add(searchResultsList);
}
}

 

Once you have the list you can convert the list into JSON using Gson and then use it wherever you want.

 

Gson gson = new Gson();
String jsonString = gson.toJson(searchResultsLists); // This will return JSON response of the POJO or VO.

 

Avatar

Correct answer by
Community Advisor

Hi @TB3dock 

 

Reposting my answers here:

First you can make a VO or POJO class with all the required fields. Let's say I want to keep page title and page link for now. You can add all the fields that you want.

 

public class SearchResultsList {

private String pageTitle;
private String pageLink;

public String getPageTitle() {
return pageTitle;
}

public void setPageTitle(String pageTitle) {
this.pageTitle = pageTitle;
}

public String getPageLink() {
return pageLink;
}

public void setPageLink(String pageLink) {
this.pageLink = pageLink;
}

@Override
public String toString() {
return "SearchResultsList{" +
"pageTitle='" + pageTitle + '\'' +
", pageLink='" + pageLink + '\'' +
'}';
}
}

 

You can create a search service and write the required logic to search here. I am not adding the details here. Predicates and all will go here.

Now call the search service and then get the results.

final SearchResult searchResults = searchService.getSearchResults(resourceResolver, searchRootPath); // whatever you want here can be performed inside the service

 

Once you have the search result preapre the desired result by parsing the raw search result:

 

private List<SearchResultsList> parseResults(SearchResult searchResult, ResourceResolver resourceResolver) {
List<SearchResultsList> searchResultsLists = new ArrayList<>();
totalResult = searchResult.getTotalMatches();
final List<Hit> hits = searchResult.getHits();
try {
for (Hit hit : hits) {
final Resource hitResource = hit.getResource();
if (hitResource != null) {
final Page page = getPage(hitResource);
if (page != null) {
final Resource contentResource = page.getContentResource();
getResultList(resourceResolver, searchResultsLists, hit, hitResource, contentResource);
}
}
}
} catch (RepositoryException e) {
log.error("***** :: parseResult :: Exception *****", e);
}
return searchResultsLists;
}

 

private void getResultList(ResourceResolver resourceResolver, List<SearchResultsList> searchResultsLists, Hit hit, Resource hitResource, Resource contentResource) throws RepositoryException {
if (contentResource != null) {
final ValueMap pageValueMap = contentResource.getValueMap(); // This will give the page property

SearchResultsList searchResultsList = new SearchResultsList();
final String pageTitle = pageValueMap.get(NameConstants.PN_PAGE_TITLE) != null ? pageValueMap.get(NameConstants.PN_PAGE_TITLE).toString() : pageValueMap.get(NameConstants.PN_TITLE).toString();
searchResultsList.setPageTitle(pageTitle);
searchResultsList.setPageLink(StringUtils.isNotBlank(hitResource.getPath()) ? LinksUtil.checkInternalURLByPath(hitResource.getPath(), resourceResolver) : StringUtils.EMPTY); // This will give the page path or link
// rest all can be added here whatever you have in the POJO class.

searchResultsLists.add(searchResultsList);
}
}
private Page getPage(Resource resource) {
if (resource != null) {
ResourceResolver resourceResolver = resource.getResourceResolver();
PageManager pageManager = resourceResolver.adaptTo(PageManager.class);
if (pageManager != null) {
return pageManager.getContainingPage(resource);
}
}
return null;
}

Once you have the list you can convert the list into JSON using Gson and then use it wherever you want.

 

Gson gson = new Gson();
String jsonString = gson.toJson(searchResultsLists); // This will return JSON response of the POJO or VO.

 

Avatar

Level 9
This is awesome work! I would never have found this stuff. so to get a resources page is pageManager.getContainingPage(resource). Is there something similar to get all the components of a page?

Avatar

Community Advisor
Yes, If you have the resource available and want to know the corresponding page, you can use this function and it will return the if any page associated with it.

Avatar

Community Advisor

Hi @TB3dock 

 

getPage(resource)

was missing in my response and I have added it back now. It's a custom method that was written.

 

getContentResource() returns the addressed resource of the page's content or null if the respective resource does not exist. It's nothing but just the jcr:content node as a resource which will be adapted into ValueMap.

 

Thanks!