如何在Cypher Neo4j中将Node的道具值与其他道具分组?

时间:2018-08-27 11:15:14

标签: database neo4j cypher

我将描述我的数据模型以及一些我想实现的东西。 我有Neo4j作为数据库,现在数据结构是不可变的,因此“仅创建其他标签更改的节点”这样的建议不适用于我的情况,对不起!

在Neo4j中,我有Node:CategoryNode:GoodsNode:Property。货物可能与财产有许多关系。例如:(:Goods {name: "Chair"})-[:PROP]-(:Property)。此Node:Goods与两个Node:Properties有关-价格和材料。您可能已经猜到了-我有很多Node:Goods,每个人都与价格和材料Node:Property有关。

我需要为此结构构建前端客户端,以便能够通过与其相关的Node:Goods来过滤Node:Property。例如,我需要使用Node:GoodsNode:Property{name:"Price"}有关联的所有{value: >40, <100}。我在这里问过这个问题,并通过@InverseFalcon得到了很好的答案:

...
WITH g, size([(g)-[:Prop]-(p:Property) WHERE p.name = "Price" AND 190 < p.value < 320 | p]) > 0 as priceRange 
WHERE priceRange
...

当我知道要过滤什么以及如何过滤时,此解决方案将非常有效。我的问题是如何按名称将所有Node:Propery值分组,以找到max和min以及将其传递给前端过滤器的变量?

我的Node:Property如下:

{
    "name":"Price",
    "type":"num", //text, bool
    "value":245
}

我期望这样的东西(但无论响应是否会那么漂亮):

{ 
    "Category": "Chair",
    "Goods": 157,
    "Properties": [
        { "Name": "Material", "type":"text", "variants": "Metal", "Oak", "Maple" },
        { "Name": "Price", "type": "num", "min": 25, "max": 490 },
        { "Name": "InStock", "type": "bool" },
        ...
    ]
}

我试图通过UNWIND和FOREACH实现这一目标,但是我找不到在FOREACH中进行RETURN的方法。感谢您的帮助和提示,谢谢!

2 个答案:

答案 0 :(得分:2)

在处理min() type:Properties时,您可以只使用max()num聚合函数。

要解决这三个变体,您可以使用如下查询:

MATCH (good:Good)
WITH good
OPTIONAL MATCH (good)-[:PROP]-(p:Property {type:'text'})
WITH good, p.name as name, collect(p.value) as variants
WITH good, collect({name:name, type:'text', variants:variants}) as properties
OPTIONAL MATCH (good)-[:PROP]-(p:Property {type:'num'})
WITH good, properties, p.name as name, min(p.value) as min, max(p.value) as max
WITH good, properties + collect({name:name, type:'num', min:min, max:max}) as properties
WITH good, properties + [(good)-[:PROP]-(p:Property {type:'bool'}) | p {.name, type:'bool'}] as properties
RETURN good, properties

答案 1 :(得分:2)

汇总时可以使用CASE:

MATCH (C:Category)
OPTIONAL MATCH (C)-[:Good]->(G:Goods)-[:Prop]->(P:Property)
WITH C, 
     count(DISTINCT G) AS cnt, 
     P.Name AS name, P.type AS type, 
     CASE WHEN P.type = "num" THEN min(P.value) ELSE null END AS min, 
     CASE WHEN P.type = "num" THEN max(P.value) ELSE null END AS max,
     CASE WHEN P.type = "text" THEN collect(P.value) ELSE null END AS variants
WITH C.name AS name, cnt, 
     {name: name, type: type, min: min, max: max, variants: variants } AS prop
RETURN {Category: name, Goods: cnt, Properties: collect(prop)} AS category