我正在使用neo4j-driver从node.js运行neo4j查询。很多事情都被简化以削减不相关的信息,但这里需要的是。
我一直在尝试进行查询以使用一些怪癖来摄取数据集,定义如下:
课程:出版物列表
发布:包含有关出版物的数据和作为作者列表的字段
作者:相关字段为 externalId 和 normalizedFullName 。
externalId 是来自数据源系统的ID。它不能保证存在,但如果存在,它将唯一地标识节点
normalizedFullName 将始终存在,并且可以假设同一作者在其出现的任何地方始终具有相同的名称;也可以接受的是,全名可能不是唯一的,并且在某些时候可以将两个不同的人存储为同一节点
作者可能只是 normalizedFullName 的出版物的一部分,并且是 normalizedFullName AND externalId 的另一部分 EM>。正如您所看到的,数据并不是非常一致,但对于我需要的目标而言,这不是问题。
看起来像这样:(不介意任何语法错误)
"curriculum": [
{
"data": {
"fieldA": "a",
"fieldB": "b"
},
"authors": [
{
"externalId": "",
"normalizedFullName": "namea namea"
},
{
"externalId": "123456",
"normalizedFullName": "nameb nameb"
}
]
},
{
"data": {
"fieldA": "d",
"fieldB": "e"
},
"authors": [
{
"externalId": "123321",
"normalizedFullName": "namea namea"
},
{
"externalId": "123456",
"normalizedFullName": "nameb nameb"
}
]
}
]
合并所有内容
合并出版物部分是微不足道的,但是对于作者来说事情变得复杂,因为我必须遵循这个逻辑(在这里简化)来合并作者:
IF author don't have externalId OR isn't already a node created with his externalId THEN
merge by normalizedFullName
ELSE IF there is already a node with this externalId THEN
merge by externalId
所以,承认我需要某种条件合并,发现它可以通过“foreach技巧”实现,我能够想出这个小怪物(评论添加澄清):
// For each publication, merge it
UNWIND {publications} as publication
MERGE (p:Publication { fieldA: publication.data.fieldA, fieldB: publication.data.fieldB })
ON CREATE SET p = publication.data
WITH p, publication.authors AS authors
// Then, for each author in this publication
UNWIND authors AS author
// IF author don't have externalId OR isn't already a node created with his externalId THEN
MATCH (a:Author) WHERE a.externalId = author.data.externalId AND a.externalId <> '' WITH count(a) as found, author, p
// Merge by name
FOREACH(ignoreMe IN CASE WHEN found = 0 THEN [1] ELSE [] END |
MERGE (aa:Author { normalizedFullName: author.data.normalizedFullName })
ON CREATE SET aa = author.data
MERGE (aa)-[:CONTRIBUTED]->(p)
)
// Else, merge by externalId
FOREACH(ignoreMe IN CASE WHEN found > 0 THEN [1] ELSE [] END |
MERGE (aa:Author { externalId: autor.dadta.externalId })
ON CREATE SET aa = author.data
MERGE (aa)-[:CONTRIBUTED]->(p)
)
注意:这不是我正在使用的真实查询,只显示确切的结构。
问题
它不起作用。它只创建出版物(相关)而不是作者。似乎MATCH,FOREACH或两者的组合正在弄乱我期望因为UNWIND而发生的循环。
我正处于无法找到正确方法的地步。我也找不到有什么问题,甚至检查可用的文档。
那么,我该怎么办?
(如果需要更多信息,请告诉我)
提前感谢任何见解!
答案 0 :(得分:0)
我认为问题(或至少一个问题)是,如果您的作者MATCH失败,该作者的整行将被删除,并且该查询的其余部分将不会为该作者执行。
尝试使用OPTIONAL MATCH代替,这将保留行并允许查询完成这些行。
至于如何进行条件密码操作的其他选项,我们实际上刚刚发布了APOC Procedures conditional cypher execution的新版本,所以当你有机会时,请查看apoc.do.when()
。
答案 1 :(得分:0)
首先:author.data.externalId
不存在。正确的属性路径是author.externalId
(没有数据)。 author.data.normalizedFullName
也一样。
我在这里模拟你的场景,把你的数据集作为参数放在Neo4j浏览器界面中。之后我运行了你的查询。正如预期的那样,作者从未被创造过。
我更正了您执行以下步骤的查询:
author.data.externalId
更改为author.externalId
,将author.data.normalizedFullName
更改为author.normalizedFullName
。MATCH (a:Author)
更改为OPTIONAL MATCH (a:Author)
,以确保即使找不到结果也会继续查询。 count(a) as found
(不是必需的)并将测试从found = 0
更改为a IS NULL
,从found > 0
更改为a IS NOT NULL
。您更正的查询:
UNWIND {publications} as publication
MERGE (p:Publication { fieldA: publication.data.fieldA, fieldB: publication.data.fieldB })
ON CREATE SET p = publication.data
WITH p, publication.authors AS authors
UNWIND authors AS author
OPTIONAL MATCH (a:Author) WHERE a.externalId = author.externalId AND a.externalId <> '' WITH a, author, p
FOREACH(ignoreMe IN CASE WHEN a IS NULL THEN [1] ELSE [] END |
MERGE (aa:Author { normalizedFullName: author.normalizedFullName })
ON CREATE SET aa = author
MERGE (aa)-[:CONTRIBUTED]->(p)
)
FOREACH(ignoreMe IN CASE WHEN a IS NOT NULL THEN [1] ELSE [] END |
MERGE (aa:Author { externalId: author.dadta.externalId })
ON CREATE SET aa = author
MERGE (aa)-[:CONTRIBUTED]->(p)
)