3

这似乎是一个相当简单的查询,但我已经为此绞尽脑汁好几个小时了。我有一个类似于下面的节点结构:

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

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

询问

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

错误:

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

感谢任何帮助,因为我在过去的几天里一直在做这件事。

4

2 回答 2

7

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

您的查询尝试ISCHILDNODE连接条件中使用,这需要两个参数:子节点的选择器名称和父节点的选择器名称。

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

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 所期望的形式:错误表明查询定义了多个选择器,因此选择器必须作为第一个参数提供。

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

于 2014-06-01T02:07:09.533 回答
1

如果您在具有多个选择器getNodes()的 a 上调​​用方法(在您的情况下是and ) ,则会引发此异常。如果您调用.QueryResultparentchildfindResources()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而不是 using parent.*,因此您不必调用result.getColumnNames().
  3. 查询非常复杂,调用它的方式更加复杂。为什么不使用 Sling 方法来遍历food存储库中的空间?它似乎是遍历树的完美用例。
于 2014-05-31T20:32:00.287 回答