AEM query builder: search multiple properties - aem

How can I list all the properties and respective values for more than one property under a give node.
For example, the below code, I could search for one property only. But I need to search for 10 different property(alttext, img, promos.. etc) and get respective values(if exist) for it.
Map<String, String> map = new HashMap<String, String>();
map.put(TYPE_PREDICATE, "nt:base");
map.put(PATH_PREDICATE, printAttachmentJsonNodePath);
map.put("property", "fileReference");
map.put("p.excerpt", "true");
map.put(SEARCH_LIMIT_PREDICATE, "-1");
Query query = queryBuilder.createQuery(PredicateGroup.create(map),
resourceResolver.adaptTo(Session.class));
SearchResult result = query.getResult();
for (Hit hit : result.getHits()) {
String path = hit.getPath();
Resource resourceHit = resourceResolver.getResource(path);
Node node = resourceHit.adaptTo(Node.class);
String fileReference = node.getProperty("fileReference").getString();
System.out.println(fileReference);
}

you can use numerical prefixes for multiple properties:
map.put("1_property", "jcr:content/cq:template");
map.put("1_property.value", "/apps/geometrixx/templates/homepage");
map.put("2_property", "jcr:content/jcr:title");
map.put("2_property.value", "English");
here is documentation

If you have a lot of properties, or amount of properties is generated during runtime you could use Predicate.class
Your code:
Map<String, String> map = new HashMap<String, String>();
map.put(TYPE_PREDICATE, "nt:base");
map.put(PATH_PREDICATE, printAttachmentJsonNodePath);
map.put("property", "fileReference");
map.put("p.excerpt", "true");
map.put(SEARCH_LIMIT_PREDICATE, "-1");
Query query = queryBuilder.createQuery(PredicateGroup.create(map),
resourceResolver.adaptTo(Session.class));
SearchResult result = query.getResult();
Will looks in the following way:
PredicateGroup rootGroup = new PredicateGroup();
rootGroup.add(new Predicate("type").set("type", "nt:base"));
rootGroup.add(new Predicate("path").set("path", printAttachmentJsonNodePath));
rootGroup.add(new Predicate("property").set(property, "fileReference"));
rootGroup.add(new Predicate("property").set(property, "property1").set("value", value1));
.....
rootGroup.add(new Predicate("property").set(property, "propertyN").set("value", valueN));
rootGroup.set(Predicate.PARAM_EXCERPT, Boolean.TRUE.toString());
rootGroup.set(Predicate.PARAM_LIMIT, "-1");
Query query = queryBuilder.createQuery(rootGroup);
query.setHitsPerPage(limit); // also you could put limit here
SearchResult result = query.getResult();
...........
In this case AND condition will be created betwean properties : #property1=value1 AND #property2=value2
If you want OR, create separate group and add it to the root group:
PredicateGroup properties = new PredicateGroup();
properties.add(new Predicate("property").set(property, "property1").set("value", value1));
.....
properties.add(new Predicate("property").set(property, "propertyN").set("value", valueN));
properties.setAllRequired(false);
rootGroup.add(properties);

Related

Hapi Fhir query with AND / OR with map

Using Hapi Fhir, I try to write a query to use a map to pass in where condition, as follow:
Map<String, List<IQueryParameterType>> hmParameter = criteria.getMapForWhere();
Bundle bundle = fhirClientR4Configuration.clientFhihrR4().search().forResource(ServiceRequest.class)
.where(hmParameter).returnBundle(Bundle.class).execute();
My criteria object has a method getMapForWhere() where I populate this map with information inside my wrapper front end object as follow:
public Map<String, List<IQueryParameterType>> getMapForWhere() {
Map<String, List<IQueryParameterType>> hmOut = new HashMap<String, List<IQueryParameterType>>();
// Adding STATUS
if (this.status != null && !this.status.equals("")) {
StringParam sp = new StringParam();
sp.setValue(this.status);
List<IQueryParameterType> lst = new ArrayList<IQueryParameterType>();
lst.add(sp);
hmOut.put(ServiceRequest.SP_STATUS, lst);
}
// Adding INTENT
if (this.intent != null && !this.intent.equals("")) {
StringParam sp = new StringParam();
sp.setValue(this.intent);
List<IQueryParameterType> lst = new ArrayList<IQueryParameterType>();
lst.add(sp);
hmOut.put(ServiceRequest.SP_INTENT, lst);
}
return hmOut;
}
This code works fine when I want to wirte a query with all AND.
But if I want to add another condition as follow:
List<IQueryParameterOr> lstOr = new ArrayList<IQueryParameterOr>();
StringOrListParam lstServices = new StringOrListParam();
StringParam sp = new StringParam();
StringParam sg = new StringParam();
sp.setValue(MEDICAL_SERVICE_PAI);
sg.setValue(SOCIAL_SERVICE_PAI);
lstServices.addOr(sp);
lstServices.addOr(sg);
lstOr.add(lstServices);
hmOut.put(ServiceRequest.SP_CATEGORY, lstOr);
Obviously hmOut goes in error because definition of that map is different. But I don't know how to convert IParameterOr with IParameterType.

SQL2 query to search current path(defined in pathfield or RTE) in path

How to perform the following using sql2 query:
Requirement:
path: /content/consumer
go one node level, for example : /content/consumer/en-us
search for String authored in a pathfield like "/content/consumer/en-us"
if (current Node != Pathfield) then display it.
repeat the step from 1 to 3 all other locales(en-ca, fr-fr, de-de etc).
Here is what I have tried:
SELECT parent.* FROM [nt:unstructured] AS parent INNER JOIN [nt:unstructured] AS child ON ISDESCENDANTNODE(child,parent) WHERE ISDESCENDANTNODE(parent, [/content/consumer/en-us/]) AND child.[*] = '/content/consumer/%'
The query read or traversed more than 100000 nodes. To avoid affecting other tasks, processing was stopped.
If I run:
SELECT * FROM [nt:unstructured] AS s WHERE ISDESCENDANTNODE('/content/consumer/en-us/ip') and s.* LIKE '/content/consumer/%'
This will display all paths irrespective of local. What I am looking for is:
/content/consumer/[^en-us]% (i.e not like en-us).
Here is what I have done so far:
Resource resource = request.getResourceResolver().getResource(path);
Node node = resource.adaptTo(Node.class);
ResourceResolver resourceResolver = request.getResourceResolver();
try {
NodeIterator list = node.getNodes();
while (list.hasNext()) {
Node currentSubNode = list.nextNode();
subNodeName = currentSubNode.getPath();
culture = extractCultureNodeName(subNodeName);
fullTextPath = path + culture;
Map<String, String> map = new HashMap<String, String>();
map.put("type", "nt:base");
map.put("path", subNodeName);
map.put("fulltext", fullTextPath);
if (StringUtils.isNotBlank(culture)) {
Query query = queryBuilder.createQuery(PredicateGroup.create(map),
resourceResolver.adaptTo(Session.class));
SearchResult result = query.getResult();
for (Hit hit : result.getHits()) {
String output = hit.getPath();
LOG.info("HITs: " + hit.getPath());
}
}
}
The problem is in the query builder, the number of hits I am getting is far less than bare xpath query in crxde:
/jcr:root/content/consumer/en-us//element(*, nt:base)
[
(jcr:contains(., ‘/content/consumer/en-us’))
]

Linq query in stored procedure result set Ado.Net

I have a stored procedure with multiple joins, pulling all the data into a resultset I.e in dataset, now I want to write a linq query over it. How can I do that?
I am expecting:
IEnumerable<SomeType> result;
[where I need to know how the Properties of SomeType are defined.]
This is what I have tried but it does not look efficient.
SqlCommand cmd = new SqlCommand("Select top 10 * from trade");
cmd.Connection = con;
if (con.State != ConnectionState.Open)
{
con.Open();
}
SqlDataReader dr = cmd.ExecuteReader();
DataTable dt = new DataTable();
dt.Load(dr);
var result = dt.AsEnumerable();
string valresukir = string.Empty;
var sortResult = result.OrderBy(x => Convert.ToInt32(x["trade_num"]) > 12);
string valuedata = string.Empty;
foreach (var i in sortResult)
{
valuedata += i["trade_num"].ToString();
}
to can write linq query on data table like
var data= from dataRow in dt.AsEnumerable()
where dataRow.Field<int>("trade_num") > 12
select dataRow
if trade_num is integer . Take it as a example and add your conditions accordingly.
Hope it will help you.

How do I add a linked document to a linked list using the Java API for OrientDB?

I have an OType.LINKLIST field children in a class.
I can use the following command to update it:
update <parent_rid> add children = <child_rid>
But I don't know how to do this without using SQL, which is my goal.
code
ODocument doc=new ODocument("ClassA");
ODocument parentDoc=db.load(new ORecordId(rid));
How do I add doc to parentDoc's field children without using SQL?
create class Doc
create class ParentDoc
create property ParentDoc.children LINKLIST
insert into Doc set name = 'doc1' #12:0
insert into Doc set name = 'doc2' #12:1
insert into ParentDoc set name = 'pd', children = [#12:0] #13:0
update #13:0 add children = #12:1
For what I understood you want a piece of code that replaces the last four commands using Java Document API.
try (ODatabaseDocument db = new ODatabaseDocumentTx("remote:localhost/DB")) {
db.open("admin", "admin");
ODocument doc1 = new ODocument("Doc");
doc1.field("name", "doc1");
doc1.save();
List<OIdentifiable> linklist = new ArrayList();
linklist.add(doc1);
ODocument parent = new ODocument("ParentDoc");
parent.field("children", linklist, OType.LINKLIST);
parent.save();
// ...
ODocument doc2 = new ODocument("Doc");
doc2.field("name", "doc2");
doc2.save();
List children = parent.field("children");
children.add(doc2);
parent.field("children", children);
parent.save();
}

How can I transform a List<string> into XML using Linq?

The inverse question of How can I transform XML into a List or String[]?.
I have a List<string> of users and want to convert them to the following xml :
<Users>
<User>Domain\Alice</User>
<User>Domain\Bob</User>
<User>Domain\Charly</User>
</Users>
I am currently wrapping this list in a class and use XmlSerializer to solve this but I find this quite heavy ...
So is there a more straightforward solution using Linq to Xml ?
XElement xml = new XElement("Users",
(from str in aList select new XElement("User", str)).ToArray());
This might do it. Not sure if the .ToArray is necessary.
List<User> list = new List<User>();
list.Add(new User { Name = "Domain\\Alice" });
list.Add(new User { Name = "Domain\\Bob" });
list.Add(new User { Name = "Domain\\Charly" });
XElement users = new XElement("Users");
list.ForEach(user => { users.Add(new XElement("User", user.Name)); });
Console.WriteLine(users);