2017-05-24 5 views
1

저는 neo4j 드라이버를 사용하여 node.js에서 neo4j 쿼리를 실행하고 있습니다. 많은 정보가 무의미한 정보를 삭제하기 위해 단순화되었지만 필요한 것은 여기에 있습니다.UNWIND를 사용하여 MATCH와 두 개의 FOREACH로 구성된 블록을 실행하는 방법은 무엇입니까?

교육 과정 : 간행물의 목록이

는 출판 :는 게시에 대한 데이터를 포함 나는 다음과 같이 정의, 몇 가지 단점과 데이터 세트를 섭취하는 쿼리를 만들려고 한

그리고 저자

의 목록

저자 인 필드 : 관련 필드는 외부 ID정규화 된 전체 이름.

  • 는 외부 ID은 데이터의 출처 시스템에서 오는 ID입니다. 존재하는 것으로 보장되지 않지만이 경우, 그것은 고유 항상 존재하는 노드

  • normalizedFullName을 확인하고이 나타나는 곳마다 항상 같은 이름을 가질 것 같은 저자를 가정하는 괜찮습니다; 그것은 또한 전체 이름이 고유하지 않을 수 있음을 허용하고이 어떤 점에서 서로 다른 두 사람이 같은 노드로 저장 될 수

  • 저자 발행물의 일부가 될 것은 단지 그것을 normalizedFullName입니다 가능합니다으로 정규화 된 전체 이름externalId으로 다른 사람의 일부가 될 수 있습니다. 보시다시피, 매우 일관된 데이터는 아니지만, 필요한 끝 부분에는 문제가되지 않습니다.이 부분은 사소한 게시를 병합

    모두에게 병합

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

참고 : 이것은 실제 검색어가 아니며 정확한 구조를 보여줍니다.

문제점

그것은 작동하지 않습니다. 출판물은 (corretly) 작성하고 저자는 절대 작성하지 않습니다.MATCH, FOREACH 또는 둘 다의 조합이 UNWIND 때문에 일어날 것으로 예상되는 루프를 어지럽히는 것 같습니다.

나는 제대로 할 수있는 방법을 찾지 못했습니다. 나는 또한 무엇이 잘못되었는지를 발견 할 수 없으며 심지어 이용 가능한 문서를 점검한다.

그럼 어떻게해야합니까?

어떤 통찰력 사전에

감사 (나를 더 이상 정보가 필요한 경우 알려주세요)!

+0

는 여기 재현 할 수있는 작업 예를 가지고 있습니까? 매우 유용 할 것입니다! 감사! –

+0

나는 약 12 ​​시간 안에 무엇인가를 함께 집어 넣을 수있을 것이다. 고맙습니다! –

답변

0

우선 : author.data.externalId는 존재하지 않습니다. 올바른 속성 경로는 author.externalId (데이터 없음)입니다. author.data.normalizedFullName도 마찬가지입니다.

Neo4j 브라우저 인터페이스에서 데이터 세트를 매개 변수로 사용하여 시나리오를 시뮬레이트했습니다. 그 후에 당신의 질문을 실행했습니다. 예상대로 작성자는 생성되지 않습니다.

  1. author.normalizedFullNameauthor.externalIdauthor.data.normalizedFullNameauthor.data.externalId을 변경 :

    나는 다음 단계를 수행하여 쿼리를 수정했습니다.
  2. MATCH (a:Author)에서 OPTIONAL MATCH (a:Author)으로 변경하여 결과가 없어도 쿼리가 계속 진행되도록합니다.
  3. count(a) as found (필요 없음)을 제거하고 변경된 테스트를 found = 0에서 a IS NULLfound > 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) 
) 

내가이 쿼리 실행 후 생성 된 데이터 세트 : enter image description here

+0

그것은 효과가있다! OPTIONAL MATCH에 대한 MATCH를 바꾸면 작동합니다. 그러나 나는 또한 당신의 다른 설득을 구현할 것입니다. 많은 감사합니다! –

+0

당신은 wolcome입니다! :) –

0

필자의 MATCH가 실패하면 해당 작성자의 전체 행이 지워지고 나머지 쿼리는 해당 작성자를 위해 실행되지 않는다고 생각합니다.

대신에 OPTIONAL MATCH를 사용하면 행을 보존하고 해당 행에 대한 쿼리를 완료 할 수 있습니다.

조건부 키퍼 작업을 수행하는 방법에 대한 추가 옵션은 실제로 의 새 버전을 conditional cypher execution과 함께 출시 했으므로 기회가되면 apoc.do.when()을 살펴보십시오.

+0

효과가있었습니다! 나는 그것이 그렇게 단순하다고 믿을 수 없다. MATCH를 OPTIONAL MATCH로 바꾸면 모든 것이 완벽하게 작동합니다. 많은 감사합니다! –