Silta
Silta

Reputation: 99

Neo4j group nodes with property

In Neo4j, I want to create a query that returns nodes grouped on common property without altering my graph. For example, if I have the following graph where each person has a property corresponding to his department in the company:

enter image description here

I want my query to return a graph like the following, where the nodes are replaced by the property and where the weight of the edges corresponds to the number of relations:

enter image description here

Do you have any idea how to proceed? I looked at APOC nodes collapse without success.

Upvotes: 1

Views: 405

Answers (3)

jose_bacoy
jose_bacoy

Reputation: 12704

This is the way to return the subgraph using apoc.nodes.collapse.

MATCH (p:Person)-[:R]->(c:Person)
WITH c, collect(p) as subgraph 
CALL apoc.nodes.collapse(subgraph,{properties:'combine', countMerge:false}) 
YIELD from, rel, to WHERE to is not null
RETURN from, rel, to 

Result:

enter image description here

Creating the nodes WITH relationship weights can be done this way. Unfortunately, apoc.nodes.collapse is not returning relationship weights that you described. But apoc.collapse can count the number of nodes that are merged using countMerge:true.

MATCH (p:Person)-[:R]->(c:Person)
WITH c, collect(p) as subgraph, count(distinct p) AS relweight
WITH c.department as relto, [s in subgraph|s.department][0] as relfrom, relweight 
MERGE (d1:Department {name: relfrom})
MERGE (d2:Department {name: relto})
MERGE (d1)-[r:newR{wt: relweight}]->(d2)
RETURN d1, d2, r

Result:

enter image description here

Upvotes: 1

Graphileon
Graphileon

Reputation: 5385

If you want to "return nodes without altering the graph", the way to go is through so-called virtual nodes and relationships. These are nodes/rels that quack like real ones, but only exist in memory.

any other mechanism (including the collapse), alters the graph.

More on virtual node / rels can be found here : https://neo4j.com/labs/apoc/4.4/virtual/

The above approach can be used with pure Neo4j tools. There are other vizualisation layers (like Graphileon : disclosure I work for them) that offer even more possibilities if you need more advanced interaction.

Upvotes: 1

Charchit Kapoor
Charchit Kapoor

Reputation: 9284

It is possible using, Cypher as well. I created your graph using the following Cypher query, locally:

MERGE (p:Person{name: 'Alex', department: 'HR'})
MERGE (p1:Person{name: 'John', department: 'HR'})
MERGE (p2:Person{name: 'Kate', department: 'IT'})
MERGE (p3:Person{name: 'Mike', department: 'Sales'})
MERGE (p1)-[:R]->(p3)
MERGE (p1)-[:R]->(p2)
MERGE (p2)-[:R]->(p1)
MERGE (p)-[:R]->(p2)

Now, to convert it into the desired graph, you can try the following Cypher query:

MATCH (p:Person)
WITH distinct p.department AS departmentName
MERGE (d:Department{name: departmentName}) <-- First create all the distinct department nodes
WITH COLLECT(departmentName) AS departments
UNWIND departments AS departmentName
MATCH (p:Person{department:departmentName})
OPTIONAL MATCH (p)<-[:R]-(p1:Person)
WITH departmentName, p1 WHERE p1 IS NOT NULL
WITH departmentName, p1.department AS sourceDepartment, count(distinct p1) AS relCount <-- For each department find out the number of distinct incoming relations, with respect to each department
MATCH (d1:Department{name: departmentName})
MATCH (d2:Department{name: sourceDepartment})
MERGE (d1)<-[:R{count: relCount}]-(d2) <-- Create the relationships between department and store the count in the relationship

To check the department nodes, and verify them, run this:

MATCH (n:Department) RETURN n

In the end, if required you can delete all the Person nodes, like this:

MATCH (n:Person) DETACH DELETE n

Upvotes: 1

Related Questions