【问题标题】:Neo4j Cypher multiple WITH keywordsNeo4j Cypher 多个 WITH 关键字
【发布时间】:2025-11-21 18:10:01
【问题描述】:

我有以下 Neo4j Cypher 查询:

MATCH (parentD:Decision)-[:CONTAINS]->(childD:Decision) 
WHERE id(parentD) = {parentDecisionId} 
WITH childD, parentD 
OPTIONAL MATCH (parentD)<-[:DEFINED_BY]-(c:Criterion)<-[:VOTED_ON]-(vg:VoteGroup)-[:VOTED_FOR]->(childD) 
OPTIONAL MATCH (parentD)<-[:DEFINED_BY]-(ch:Characteristic)<-[:SET_ON]-(v:Value)-[:SET_FOR]->(childD) 
WITH childD, {criterion: c,  weight: vg.avgVotesWeight} AS weightedCriterion, {characteristic: ch,  value: v.value} AS valuedCharacteristic 
RETURN childD AS decision, collect(weightedCriterion) AS weightedCriteria, collect(valuedCharacteristic) AS valuedCharacteristics

因此,在我的 SDN 4 项目中,我希望检索 List&lt;DecisionMatrix&gt;

@QueryResult
public class DecisionMatrix {

    private Decision decision;

    private List<WeightedCriterion> weightedCriteria;

    private List<ValuedCharacteristic> valuedCharacteristics;

}

@QueryResult
public class WeightedCriterion {

    private Criterion criterion;

    private Double weight;

}

@QueryResult
public class ValuedCharacteristic {

    private Characteristic characteristic;

    private Object value;
}

现在这个查询返回一个正确的标准列表,但一个错误的列表,其中包含一个空的特征元素。

例如,我没有任何与此查询条件匹配的特征,但在结果中我可以看到以下结构,其中包含两条记录:

RDBMS : [{criterion=Node[161], weight=4.333333333333333}, {criterion=Node[160], weight=2.1666666666666665}] : [{characteristic=null, value=null}, {characteristic=null, value=null}]

NoSQL : [{criterion=Node[160], weight=4.333333333333333}, {criterion=Node[161], weight=2.5}, {criterion=Node[162], weight=4.2}] : [{characteristic=null, value=null}, {characteristic=null, value=null}, {characteristic=null, value=null}]

结果包含一组正确的RDBMS(2 个条件)和NoSQL(3 个条件)的条件,但一组错误的特征。我希望这两个记录都有一个空的特征列表(0 个元素)(这些节点没有关联的特征)。但在第一条记录中,我有 2 个空特征(与标准相同的列表长度)和 3第二条记录的空特征。

我做错了什么以及如何解决?

【问题讨论】:

    标签: neo4j cypher spring-data-neo4j-4


    【解决方案1】:

    这是在此处为值显式创建映射的结果:

    ... {characteristic: ch,  value: v.value} AS valuedCharacteristic ...
    

    这会创建一个映射,并相应地设置值,而这些值恰好为 null,因为 OPTIONAL MATCH 无法匹配该模式。将空值添加到地图中没有任何问题,并且地图的存在与它的一个(甚至全部)属性值是否为空没有内在联系。

    对于 Neo4j 3.1 及更高版本,解决此问题并确保在没有特征时最后的列表保持为空的最简单方法是完全跳过 OPTIONAL MATCH,并改用 pattern comprehension。我们也可以对您的其他 OPTIONAL MATCH 使用 :Criterion 和 :VoteGroup 做同样的事情。

    MATCH (parentD:Decision)-[:CONTAINS]->(childD:Decision) 
    WHERE id(parentD) = {parentDecisionId} 
    RETURN childD AS decision,
    [ (parentD)<-[:DEFINED_BY]-(c:Criterion)<-[:VOTED_ON]-(vg:VoteGroup)-[:VOTED_FOR]->(childD) 
      | {criterion: c,  weight: vg.avgVotesWeight} ] AS weightedCriteria, 
    [ (parentD)<-[:DEFINED_BY]-(ch:Characteristic)<-[:SET_ON]-(v:Value)-[:SET_FOR]->(childD) 
      | {characteristic: ch,  value: v.value} ] AS valuedCharacteristics
    

    如果您的模式推导中的模式不存在,则结果列表将为空。

    对于 Neo4j 3.0 及更低版本,您可能必须坚持使用原始查询,但在相应变量为空时使用 CASE 语句有条件地发出 null 而不是您的 valuedCharacteristic(和 weightedCriterion)映射。使用它的截图如下所示:

    ... CASE WHEN ch IS NULL THEN null ELSE {characteristic: ch,  value: v.value} END AS valuedCharacteristic
    

    【讨论】:

    • 非常感谢!这正是我所需要的。我使用 Neo4j 3.1