Virtual Nodes/Rels
Virtual Nodes and Relationships don’t exist in the graph, they are only returned to the UI/user for representing a graph projection. They can be visualized or processed otherwise. Please note that they have negative id’s.
Function Overview
Qualified Name | Type | Release |
---|---|---|
apoc.create.vNode |
|
|
apoc.create.vNode |
|
|
|
|
|
apoc.create.virtual.fromNode |
|
|
apoc.create.vRelationship |
|
|
apoc.create.vRelationship |
|
|
|
|
|
|
|
|
|
|
Virtual Nodes/Rels Example
vNode
, vRelationship
From this simple data set:
CREATE (from:Account), (to:Account)
WITH from, to
CREATE (from)-[:SENT]->(:Payment {amount: 250})-[:RECEIVED]->(to)
CREATE (from)-[:SENT]->(:Payment {amount: 750})-[:RECEIVED]->(to)
we can do:
MATCH (from:Account)-[:SENT]->(p:Payment)-[:RECEIVED]->(to:Account)
RETURN from, to, apoc.create.vRelationship(from,'PAID',{amount:sum(p.amount)},to) as rel;

From this simple data set:
CREATE (:Person {country: "Test1"})-[:KNOWS]->(:Person {country: "Test2"}),
(:Person {country: "Foo"})-[:KNOWS]->(:Person {country: "Bar"})
we can execute:
MATCH (p:Person) WITH collect(distinct p.country) as countries
WITH [cName IN countries | apoc.create.vNode(['Country'],{name:cName})] as countryNodes
WITH apoc.map.groupBy(countryNodes,'name') as countries
MATCH (p1:Person)-[:KNOWS]->(p2:Person)
WITH p1.country as cFrom, p2.country as cTo, count(*) as count, countries
RETURN countries[cFrom] as from, countries[cTo] as to, apoc.create.vRelationship(countries[cFrom],'KNOWS',{count:count},countries[cTo]) as rel;

That’s of course easier with apoc.nodes.group
.
From a simple data set
CREATE(a:Person)-[r:ACTED_IN]->(b:Movie)
We can create a virtual copy, adding as attribute name
the labels value
MATCH (a)-[r]->(b)
WITH head(labels(a)) AS l, head(labels(b)) AS l2, type(r) AS rel_type, count(*) as count
CALL apoc.create.vNode([l],{name:l}) yield node as a
CALL apoc.create.vNode([l2],{name:l2}) yield node as b
CALL apoc.create.vRelationship(a,rel_type,{count:count},b) yield rel
RETURN *;

Virtual nodes and virtual relationships have always a negative id |

Virtual nodes can also be built from existing nodes, filtering the properties in order to get a subset of them. In this case, the Virtual node keeps the id of the original node.
MATCH (node:Person {name:'neo', age:'42'})
return apoc.create.virtual.fromNode(node, ['name']) as person
virtualPath
CALL apoc.create.virtualPath(['British','Person'],{name:'James', age:28},'KNOWS',{since:2009},['Swedish','Person'],{name:'Daniel', age:30})

We can create a virtual pattern from an existing one
CREATE(a:Person {name:'Daniel'})-[r:KNOWS]->(b:Person {name:'John'})
From this dataset we can create a virtual pattern
MATCH (a)-[r]->(b)
WITH head(labels(a)) AS labelA, head(labels(b)) AS labelB, type(r) AS rel_type, a.name AS aName, b.name AS bName
CALL apoc.create.virtualPath([labelA],{name: aName},rel_type,{since:2009},[labelB],{name: bName}) yield from, rel, to
RETURN *;
To update a virtual node you can use the apoc.create.setProperty or apoc.create.setProperties, otherwise for a virtual relationships the apoc.create.setRelProperty or apoc.create.setRelProperties |