如何在 Neo4J 中使用 Cypher 向现有节点添加多个值

How to add multiple values to existing nodes with Cypher in Neo4J

我正在尝试在 Neo4J 中加载一些数据。我有一个已经设置好的 Person 节点。现在,这个节点需要有一个 email 属性 ,它应该是一个数组(或集合)。基本上,email 属性 需要有多个值,比如 -

email: ["abc@xyz.com", "abc@foo.com"]

我在这里遇到过类似的问题,但所有答案都表明在创建节点时 属性 设置多个 属性 值 。喜欢来自 this 答案的查询 -

CREATE (e:Employee { name:"Sam",languages: ["C", "C#"]})
RETURN e

但我的问题是 Person 节点 已经创建 ,我需要设置 email 属性现在。

这是我必须加载的数据的一小部分 -

 Personid|email 
933|Mahinda933@hotmail.com 
933|Mahinda933@yahoo.com
933|Mahinda933@zoho.com 
1129|Carmen1129@gmail.com
1129|Carmen1129@gmx.com 
1129|Carmen1129@yahoo.com
4194|Ho.Chi4194@gmail.com 
4194|Ho.Chi4194@gmx.com

此外,数据来自包含数千行的 CSV 文件,因此我的查询需要通用,我无法为每个单独的 Person 节点设置属性。

当我用这个子集测试电子邮件 属性 的创建时,我的第一次尝试是这样的 -

 MATCH (n:TESTPERSON{id:933})
 SET n.email = "Mahinda933@hotmail.com"
 RETURN n

 MATCH (n:TESTPERSON{id:933})
 SET n.email = "Mahinda933@yahoo.com"
 RETURN n

如我所想,这只是将 email 属性 覆盖为最近查询中的值。

查看此处和 Cypher 文档上的答案后,我发现 Neo4J 允许您将 array/collection(同一类型的多个值)设置为 属性 值,并且然后我尝试了这个 -

 // CREATE test node
 CREATE (n:TESTPERSON{id:933})
 RETURN n

 // at this time, this node does not have any `email` property, so setup 
 // email as an array with one string value
 MATCH (n:TESTPERSON{id:933})
 SET n.email = ["Mahinda933@hotmail.com"]
 RETURN n


 // Now, using +=, I can append to the array of strings
 MATCH (n:TESTPERSON{id:933})
 SET n.email = n.email + "Mahinda933@yahoo.com"
 RETURN n

 // add a third value to array
 MATCH (n:TESTPERSON{id:933})
 SET n.email = n.email + "Mahinda933@zoho.com"
 RETURN n

这是结果 -

如您所见,email 属性 现在有多个值。

但问题是,由于我的 CSV 文件有数千行,我需要一个通用查询来执行此操作。

我想根据文档 here 使用 CASE 语句,并尝试了这个 -

MATCH (n:TESTPERSON {id:933}) 
CASE 
WHEN n.email IS NULL THEN SET n.email = [ "Mahinda933@hotmail.com"] 
ELSE SET n.email = n.email + "Mahinda933@yahoo.com" 
RETURN n

但这只会抛出错误 - mismatched input CASE expecting ;

我希望我可以像这样将此查询用作我的 CSV 文件的通用方式 -

LOAD CSV WITH HEADERS FROM 'FILEURL' AS line FIELDTERMINATOR `|`
MATCH (n:TESTPERSON {id:toInt(line.Personid)}) 
CASE 
WHEN n.email IS NULL THEN SET n.email = [line.email] 
ELSE SET n.email = n.email + line.email 

但我什至不知道这是否可行,即使 CASE 错误已修复。

我真的很困惑,非常感谢任何帮助。谢谢。

使用 MERGE 尝试此解决方案:

LOAD CSV WITH HEADERS FROM 'file:///p.csv' AS line FIELDTERMINATOR '|'
MERGE (p:Person {id:toInteger(line.Personid)})
ON CREATE SET p.mail = line.email
ON MATCH SET p.mail = p.mail + '-' + line.email

MERGE 命令处理重复节点,然后我们仅在使用 ON CREATE SET 创建节点时设置属性,并且当节点已经在数据库中时(即 ON MATCH SET),我们将把电子邮件地址添加到 属性。

希望对您有所帮助。

这是我在 Neo4j 中的结果:

一个快速的解决方法是分两步加载数据

1/ LOAD CSV,用空数组创建节点属性

2/再次加载 CSV,设置电子邮件 +=

3/ 可选,根据每个节点的数据,删除数组中的双精度数(使用自定义过程)。

应该做的。我对 CASE 语法也不是很满意

您可以使用 COALESCE() 来使用默认值,以防您尝试获取的值为空。您可以这样使用它:

... SET n.email = COALESCE(n.email, []) + "Mahinda933@yahoo.com" ...

每当将值数组设置为节点 属性 时,最好考虑一下是否可以将这些值建模为与原始节点有关系的单独节点。

在这种情况下,:Email 节点与您的 :TESTPERSON 节点有某种关系,每封电子邮件有一个 :Email 节点,以及从 :TESTPERSON 到多个 :Email 的多个关系。

这里的一个优势是你可以支持唯一性约束,如果你想确保系统中只有一个 :Email,并且你可以通过他们的电子邮件快速查找一个人,如果你有一个索引或唯一约束,因为查询将使用索引来查找 :Email 并且从那里它只是一个到电子邮件所有者的关系遍历。

当节点上的集合中有值时,您不能对集合中的值使用索引查找,因此您当前的模型将无法通过电子邮件快速查找人员。