ganninu93
ganninu93

Reputation: 1601

Combine query results into a unique list - Neo4j

Given a keyword, I would like to find all the papers that contain the keyword, their references and the authors of all the papers. I've tried using 3 approaches.

approach 1 combining the results into a list, but this leads to duplicate entries in the list (papers).

MATCH (k:keyword)-[AREAOF]->(f:fieldOfStudy {fieldName: "fos1"}) 
WITH k
MATCH (p:paper)-[:CONTAINS]->(k)
WITH p
MATCH (p)-[:REFERENCES]->(r:paper)
WITH p,r
MATCH (c:paper)-[:REFERENCES]->(p)
WITH [c,p,r] as papers
MATCH (a:author)-[:PUBLISHED]->(p:paper)
WHERE p in papers
return a,p

approach 2 - Using + operator I tried to do something similar to this, but I get a type mismatch error.

MATCH (k:keyword)-[AREAOF]->(f:fieldOfStudy {fieldName: "fos1"}) 
WITH k 
MATCH (p:paper)-[:CONTAINS]->(k) 
WITH p 
MATCH (p)-[:REFERENCES]->(r:paper) 
WITH p,r 
MATCH (c:paper)-[:REFERENCES]->(p) 
RETURN p+r

Error:

Type mismatch: expected List<Node> but was Node (line 8, column 14 (offset: 229))
"    return p+r"
              ^

approach 3 - using UNION

The first approach fails since each results shows the represents the connection between papers. I.e c-[:REFERENCES]->p-[:REFERENCES]->r. To obtain a 1 dimensional result I tried to use UNION. This works and obtains a unique list of the papers, however I cannot manage to use the output to query for the authors.

MATCH (k:keyword)-[AREAOF]->(f:fieldOfStudy {fieldName: "fos1"}) 
WITH k
MATCH (p:paper)-[:CONTAINS]->(k)
RETURN p as papers
UNION 
MATCH (k:keyword)-[AREAOF]->(f:fieldOfStudy {fieldName: "fos1"}) 
WITH k
MATCH (p:paper)-[:CONTAINS]->(k)
WITH p
MATCH (p)-[:REFERENCES]->(r:paper)
RETURN r as papers
UNION
MATCH (k:keyword)-[AREAOF]->(f:fieldOfStudy {fieldName: "fos1"}) 
WITH k
MATCH (p:paper)-[:CONTAINS]->(k)
WITH p
MATCH (c:paper)-[:REFERENCES]->(p)
RETURN c as papers

In this case, how can I take the final answer (papers) and find their authors? i.e

(a:author)-[:PUBLISHED]->(p:paper)
WHERE p in papers

Upvotes: 0

Views: 1643

Answers (3)

InverseFalcon
InverseFalcon

Reputation: 30397

You can actually get all the papers you need quite easily by matching from papers using a 0-1 variable relationship, and omitting direction.

Here's how that might work:

MATCH (k:keyword)-[:AREAOF]->(:fieldOfStudy {fieldName: "fos1"}) 
MATCH (p:paper)-[:CONTAINS]->(k)
WITH p
MATCH (p)-[:REFERENCES*0..1]-(paper:Paper)
WITH DISTINCT paper
MATCH (a:author)-[:PUBLISHED]->(paper)
RETURN a, paper

The key is in the undirected :REFERENCES match:

MATCH (p)-[:REFERENCES*0..1]-(paper:Paper)

This will traverse 0 to 1 :REFERENCES relationships, meaning "paper" will include p, as well as any node linked to p through a :REFERENCES relationship in either direction, so you'll get papers that referenced p as well as papers that p referenced.

Upvotes: 1

ganninu93
ganninu93

Reputation: 1601

After some further research I used approach 1 then used UNWIND to convert the answer into a single list. Since this contained duplicates, I used distinct() to filter out duplicate entries. The result is as follows

MATCH (k:keyword)-[AREAOF]->(f:fieldOfStudy {fieldName: "fos1"}) 
WITH k
MATCH (p:paper)-[:CONTAINS]->(k)
WITH p
MATCH (p)-[:REFERENCES]->(r:paper)
WITH p,r
MATCH (c:paper)-[:REFERENCES]->(p)
WITH [c,p,r] as papers
UNWIND papers as pap
WITH distinct(pap) as papers
MATCH (a:author)-[:PUBLISHED]->(p:paper)
WHERE p in [papers]
return a,p

Upvotes: 1

Gabor Szarnyas
Gabor Szarnyas

Reputation: 5047

You can collect the papers to a list:

MATCH ...
WITH somePaper, collect(p) AS papers
WHERE somePaper IN papers
RETURN somePaper

Upvotes: 0

Related Questions