SQL2 - 获取子节点属性

时间:2014-05-31 17:53:03

标签: cq5 jcr jcr-sql2

这似乎是一个相当简单的查询,但我已经在这个问题上敲了几个小时。我有一个类似于下面的节点结构:

food-group
    jcr:content
        nuts -> type=almonds
        meat -> beef=true
        fruit -> type=apples,oranges,bananas

我需要从子节点收集三种类型的属性:一个是字符串,布尔和字符串数组。我认为以下sql2查询将起作用并获取它们的属性,但无论出于何种原因我都会收到错误:

QUERY

SELECT parent.* FROM [cq:PageContent] AS parent INNER JOIN [nt:base] as child ON ISCHILDNODE(parent) WHERE ISDESCENDANTNODE(parent, [/content/grocerystore/food/])"

ERROR:

Need to specify the selector name because the query contains more than one selector.

任何帮助都会受到赞赏,因为我过去几天一直在这里。

2 个答案:

答案 0 :(得分:6)

有两个地方可以在JCR-SQL2查询中使用ISCHILDNODE函数:在WHERE子句和连接条件中。不幸的是,它们采用了不同的参数。

您的查询正在尝试使用加入条件中的ISCHILDNODE,这需要两个参数:子节点的选择器名称和父节点的选择器名称。 / p>

这是我认为你想要的查询:

SELECT parent.* 
FROM [cq:PageContent] AS parent 
INNER JOIN [nt:base] as child ON ISCHILDNODE(child,parent) 
WHERE ISDESCENDANTNODE(parent, [/content/grocerystore/food/])

唯一的变化是ISCHILDNODE功能的参数。

不幸的是,错误消息并没有真正说清楚。要理解原因,了解ISCHILDNODE的另一种形式 - WHERE子句中使用的形式是有帮助的。该表单还需要两个参数:表示子节点的选择器的名称,以及父节点的文字路径(生成的节点是子节点)。这是一个使用此表单的人为查询:

SELECT node.*
FROM [nt:base] AS node
WHERE ISCHILDNODE(node,[/content/grocerystore])

查询结果将包含/content/grocerystore节点的子节点的所有节点。

现在,如果查询只定义了一个选择器(例如,非连接),那么只有一个选择器名称可以传递给ISCHILDNODE函数。严格地说,选择器是隐式已知的,因此JCR-SQL2允许您仅传入路径。这是一个在语义上与之前设想的示例相同的查询:

SELECT node.*
FROM [nt:base] AS node
WHERE ISCHILDNODE([/content/grocerystore])

这是唯一采用单个参数的ISCHILDNODE形式,我认为这是我认为CQ5期望的形式:错误表明查询定义了多个选择器,因此选择器必须作为第一个参数提供。

当然,这是非常误导的,因为您实际上正在使用加入条件中出现的函数形式。更好的错误消息会说该函数需要子选择器名称和父选择器名称。

答案 1 :(得分:1)

如果您在具有多个选择器的getNodes()上调用QueryResult方法,则会抛出此异常(在您的情况下,parentchild )。如果您在findResources()上调用ResourceResolver,也会使用此方法。

请改用QueryResult#getRows()方法:

Session session = resourceResolver.adaptTo(Session.class);
QueryManager queryManager = session.getWorkspace().getQueryManager();
Query query = queryManager.createQuery("...", Query.JCR_SQL2);
QueryResult result = query.execute();
// consider using result.getColumnNames() here
RowIterator rows = result.getRows();
while (rows.hasNext()) {
    Row row = rows.nextRow();
    // use row.getValue() or row.getValues()
}

一些评论:

  1. 您需要修复SQL查询,将child添加为ISCHILDNODE(parent)的第一个参数。
  2. SELECT子句中传递属性列表explicite,而不是使用parent.*,因此您不必调用result.getColumnNames()
  3. 查询非常复杂,调用它的方式更加复杂。为什么不使用Sling方法迭代存储库中的food空间?它似乎是迭代树的完美用例。