如何使用UNWIND执行由MATCH和两个FOREACH组成的块?

时间:2017-05-24 01:03:15

标签: node.js neo4j cypher

我正在使用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而发生的循环。

我正处于无法找到正确方法的地步。我也找不到有什么问题,甚至检查可用的文档。

那么,我该怎么办?

(如果需要更多信息,请告诉我)

提前感谢任何见解!

2 个答案:

答案 0 :(得分:0)

我认为问题(或至少一个问题)是,如果您的作者MATCH失败,该作者的整行将被删除,并且该查询的其余部分将不会为该作者执行。

尝试使用OPTIONAL MATCH代替,这将保留行并允许查询完成这些行。

至于如何进行条件密码操作的其他选项,我们实际上刚刚发布了APOC Procedures conditional cypher execution的新版本,所以当你有机会时,请查看apoc.do.when()

答案 1 :(得分:0)

首先:author.data.externalId不存在。正确的属性路径是author.externalId(没有数据)。 author.data.normalizedFullName也一样。

我在这里模拟你的场景,把你的数据集作为参数放在Neo4j浏览器界面中。之后我运行了你的查询。正如预期的那样,作者从未被创造过。

我更正了您执行以下步骤的查询:

  1. author.data.externalId更改为author.externalId,将author.data.normalizedFullName更改为author.normalizedFullName
  2. MATCH (a:Author)更改为OPTIONAL MATCH (a:Author),以确保即使找不到结果也会继续查询。
  3. 已删除count(a) as found(不是必需的)并将测试从found = 0更改为a IS NULL,从found > 0更改为a IS NOT NULL
  4. 您更正的查询:

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

    运行此查询后创建的数据集: enter image description here