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

kgsdhlau  于 2022-11-05  发布在  其他
关注(0)|答案(3)|浏览(258)

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

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

我在这里遇到过类似的问题,但是所有的答案都表明在创建节点本身时要设置多个属性值。

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节点设置属性。
当我用这个子集测试email属性的创建时,我的第一个尝试是-

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允许您将数组/集合(同一类型的多个值)设置为属性值,然后我尝试了以下操作-

// 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

以下是结果-x1c 0d1x
如您所见,email属性现在有多个值。
但问题是,由于我的CSV文件有数千行,我需要一个通用查询来完成此操作。
我想到了使用CASE语句,就像文档here一样,并尝试了以下方法-

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错误已修复。
我真的被难住了,我会很感激任何帮助。谢谢。

nimxete2

nimxete21#

你可以使用COALESCE()来使用一个默认值,以防你试图获取的值为空。你可以这样使用它:
... SET n.email = COALESCE(n.email, []) + "Mahinda933@yahoo.com" ...
每当您将值数组设置为节点属性时,最好考虑是否可以将这些值数组建模为与原始节点具有关系的单独节点。
在本例中,:Email节点与您的:TESTPERSON节点具有某种关系,每个电子邮件具有一个:Email节点,并且:TESTPERSON与多个:Email具有多个关系。
这里的一个优点是,如果您希望确保系统中只有一个:Email,则可以支持唯一性约束。如果您有索引或唯一性约束,则可以通过电子邮件快速查找人员,因为查询将使用索引查找:Email,从那里到电子邮件的所有者只有一个关系遍历。
当节点上的集合中有值时,不能使用索引查找集合中的值,因此当前模型将无法通过电子邮件快速查找人员。

sg3maiej

sg3maiej2#

使用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中的结果:

i2byvkas

i2byvkas3#

一种快速解决方法是分两步加载数据
1/ LOAD CSV,创建数组属性为空的节点
2/再次加载CSV,设置电子邮件+=
3/可选,根据每个节点的数据,删除数组中的双精度值(使用自定义过程执行此操作)。
应该这样做。我也不是很满意CASE语法

相关问题