Creating data

The APOC library contains procedures which enhance Neo4j’s write functionality. Many of these procedures enable dynamic data creation, such as dynamically adding node labels.

For an explanation of how to create nodes and relationships dynamically using the APOC library by Michael Hunger, Senior Director of User Innovation at Neo4j, watch this video:

Functions for creating data dynamically

Qualified Name Type

apoc.create.node(label LIST<STRING>, props MAP<STRING, ANY>) - creates a NODE with the given dynamic labels.

Procedure

apoc.create.nodes(label LIST<STRING>, props LIST<MAP<STRING, ANY>>) - creates NODE values with the given dynamic labels.

Procedure

apoc.create.relationship(from NODE, relType STRING, props MAP<STRING, ANY>, to NODE) - creates a RELATIONSHIP with the given dynamic relationship type.

Procedure

apoc.create.removeLabels(nodes ANY, label LIST<STRING>) - removes the given labels from the given NODE values.

Procedure

apoc.create.removeProperties(nodes ANY, keys LIST<STRING>) - removes the given properties from the given NODE values.

Procedure

apoc.create.removeRelProperties(rels ANY, keys LIST<STRING>) - removes the given properties from the given RELATIONSHIP values.

Procedure

apoc.create.setProperties(nodes ANY, keys LIST<STRING>, values LIST<ANY>) - sets the given properties to the given NODE values.

Procedure

apoc.create.setProperty(nodes ANY, key LIST<STRING>, value ANY) - sets the given property to the given NODE values.

Procedure

apoc.create.setRelProperties(rels ANY, keys LIST<STRING>, values LIST<ANY>) - sets the given properties on the RELATIONSHIP values.

Procedure

apoc.create.setRelProperty(rels ANY, key STRING, value ANY) - sets the given property on the RELATIONSHIP values.

Procedure

apoc.nodes.link(nodes LIST<NODE>, type STRING, config MAP<STRING, ANY>) - creates a linked list of the given NODE values connected by the given RELATIONSHIP type.

Procedure

apoc.merge.relationship(startNode NODE, relType STRING, identProps MAP<STRING, ANY>, onCreateProps MAP<STRING, ANY>, endNode NODE, onMatchProps MAP<STRING, ANY>) - merges the given RELATIONSHIP values with the given dynamic types/properties.

Procedure

apoc.merge.nodeWithStats(label LIST<STRING>, identProps MAP<STRING, ANY>, onCreateProps MAP<STRING, ANY>, onMatchProps MAP<STRING, ANY>) - merges the given NODE values with the given dynamic labels. Provides queryStatistics in the result.

Procedure

apoc.merge.nodeWithStats.eager(label LIST<STRING>, identProps MAP<STRING, ANY>, onCreateProps MAP<STRING, ANY>, onMatchProps MAP<STRING, ANY>) - merges the given NODE values with the given dynamic labels eagerly. Provides queryStatistics in the result.

Procedure

apoc.merge.relationshipWithStats(startNode NODE, relType STRING, identProps MAP<STRING, ANY>, onCreateProps MAP<STRING, ANY>, endNode NODE, onMatchProps MAP<STRING, ANY>) - merges the given RELATIONSHIP values with the given dynamic types/properties. Provides queryStatistics in the result.

Procedure

apoc.merge.relationshipWithStats.eager(startNode NODE, relType STRING, identProps MAP<STRING, ANY>, onCreateProps MAP<STRING, ANY>, endNode NODE, onMatchProps MAP<STRING, ANY>) - merges the given RELATIONSHIP values with the given dynamic types/properties eagerly. Provides queryStatistics in the result.

Procedure

Examples

The below examples will further explain these procedures.

Remove Node Labels

Cypher supports deleting labels as long as the labels are hard coded. If the labels are dynamically specified, the apoc.create.removeLabels procedure can be used.

The following creates a sample graph of people:
CREATE (jennifer:Person:US {name: "Jennifer", community: 1, partition: 4})
CREATE (karin:Person:US {name: "Karin", community: 4, partition: 2})
CREATE (mark:Person:UK {name: "Mark", community: 3, partition: 3})
The following removes all labels except Person from all nodes:
CALL db.labels()
YIELD label WHERE label <> "Person"
WITH collect(label) AS labels
MATCH (p:Person)
WITH collect(p) AS people, labels
CALL apoc.create.removeLabels(people, labels)
YIELD node
RETURN node, labels(node) AS labels
Table 1. Results
node labels

(:Person {name: "Jennifer", partition: 4, community: 1})

["Person"]

(:Person {name: "Karin", partition: 2, community: 4})

["Person"]

(:Person {name: "Mark", partition: 3, community: 3})

["Person"]

Set Node and Relationship Properties

Cypher supports setting properties as long as the property names are hard coded. If the property names are dynamically specified, use the apoc.create.setProperties and apoc.create.setRelProperties procedures.

The following creates a sample graph of people:
CREATE (jennifer:Person {name: "Jennifer", community: 1, partition: 4})
CREATE (karin:Person {name: "Karin", community: 4, partition: 2})
CREATE (elaine:Person {name: "Elaine", community: 3, partition: 3})
MERGE (jennifer)-[:FRIENDS {since: datetime("2019-06-01")}]-(karin)
MERGE (jennifer)-[:FRIENDS {since: datetime("2019-05-04")}]-(elaine)
The following duplicates all node properties on Person nodes:
MATCH (p:Person)
WITH p, keys(p) AS keys
CALL apoc.create.setProperties(p,[k in keys | k + "Copy"], [k in keys | p[k]])
YIELD node
RETURN node
Table 2. Results
node

{"name":"Jennifer","partition":4,"community":1,"nameCopy":"Jennifer","partitionCopy":4,"communityCopy":1}

{"name":"Karin","partition":2,"community":4,"nameCopy":"Karin","partitionCopy":2,"communityCopy":4}

{"name":"Mark","partition":3,"community":3,"nameCopy":"Mark","partitionCopy":3,"communityCopy":3}

The following duplicates all relationship properties:
MATCH (:Person)-[friends:FRIENDS]->(:Person)
WITH friends, keys(friends) AS keys
CALL apoc.create.setRelProperties(friends,[k in keys | k + "Copy"], [k in keys | friends[k]])
YIELD rel
RETURN startNode(rel) AS start, rel, endNode(rel) AS end
Table 3. Results
start rel end

{ "name": "Jennifer", "partition": 4, "community": 1, "nameCopy": "Jennifer", "partitionCopy": 4, "communityCopy": 1 }

{ "sinceCopy": "2019-05-04T00:00:00Z", "since": "2019-05-04T00:00:00Z" }

{ "name": "Elaine", "partition": 3, "community": 3, "nameCopy": "Elaine", "partitionCopy": 3, "communityCopy": 3 }

{ "name": "Jennifer", "partition": 4, "community": 1, "nameCopy": "Jennifer", "partitionCopy": 4, "communityCopy": 1 }

{ "sinceCopy": "2019-06-01T00:00:00Z", "since": "2019-06-01T00:00:00Z" }

{ "name": "Karin", "partition": 2, "community": 4, "nameCopy": "Karin", "partitionCopy": 2, "communityCopy": 4 }

Remove Node and Relationship Properties

Cypher supports deleting properties as long as the property names are hard coded. If the property names are dynamically specified, use the apoc.create.removeProperties and apoc.create.removeRelProperties procedures.

The following creates a sample graph of people:
CREATE (jennifer:Person {name: "Jennifer", community: 1, partition: 4})
CREATE (karin:Person {name: "Karin", community: 4, partition: 2})
CREATE (elaine:Person {name: "Elaine", community: 3, partition: 3})
MERGE (jennifer)-[:FRIENDS {since: datetime("2019-06-01")}]-(karin)
MERGE (jennifer)-[:FRIENDS {since: datetime("2019-05-04")}]-(elaine)
The following deletes all properties except for name from Person nodes:
CALL db.propertyKeys()
YIELD propertyKey WHERE propertyKey <> "name"
WITH collect(propertyKey) AS propertyKeys
MATCH (p:Person)
WITH collect(p) AS nodes, propertyKeys
CALL apoc.create.removeProperties(nodes, propertyKeys)
YIELD node
RETURN node
Table 4. Results
node

{"name":"Jennifer"}

{"name":"Karin"}

{"name":"Elaine"}

The following deletes properties from all relationships:
CALL db.propertyKeys()
YIELD propertyKey
WITH collect(propertyKey) AS propertyKeys
MATCH (:Person)-[friends:FRIENDS]->(:Person)
WITH collect(friends) AS friendsRels, propertyKeys
CALL apoc.create.removeRelProperties(friendsRels, propertyKeys)
YIELD rel
RETURN startNode(rel) AS start, rel, endNode(rel) AS end
Table 5. Results
start rel end

{"name":"Jennifer"}

{}

{"name":"Elaine"}

{"name":"Jennifer"}

{}

{"name":"Karin"}

Linked Lists

apoc.nodes.link can be used to create a linked list of nodes.

The following creates a linked list of nodes:
MATCH (e:Event)
WITH e ORDER BY e.date
WITH collect(e) AS events
CALL apoc.nodes.link(events, "NEXT")
RETURN count(*);

Linked lists can also be created using Cypher.

The following creates a linked list of nodes:
MATCH (e:Event)
WITH e ORDER BY e.date
WITH collect(e) AS events, count(e) as size
CALL {
    WITH events, size
    UNWIND range(0, size - 2) as i
    WITH events[i] as a, events[i+1] as b
    MERGE (a)-[:NEXT]->(b)
}
RETURN events
linked list events