Description
When creating multiple relationships of the same type between the same two nodes using py2neo.Relationship and graph.create(), Neo4j unexpectedly overwrites the existing relationship instead of creating a new, distinct one. This behavior leads to data loss, as only the last created relationship is persisted. This appears to stem from how py2neo handles relationship equality, which is based on the start node, end node, and relationship type. The official py2neo documentation notes that this behavior differs from Neo4j itself, which permits multiple relationships of the same type between the same nodes.
Reproduction
The following Python code demonstrates the issue:
from py2neo import Graph, Relationship, Node
graph = Graph("bolt://localhost:7687", auth=("neo4j", "password"))
a = Node("Person", name="Alice")
b = Node("Person", name="Bob")
graph.merge(a, "Person", "name")
graph.merge(b, "Person", "name")
# Create two identical relationships (same start, end, type)
r1 = Relationship(a, "KNOWS", b, since=2020)
r2 = Relationship(a, "KNOWS", b, since=2021)
graph.create(r1)
graph.create(r2)
Expected Behavior
Two distinct KNOWS relationships should exist between the "Alice" and "Bob" nodes, one with the property since: 2020 and the other with since: 2021. Neo4j inherently supports parallel relationships (i.e., multiple relationships of the same type between the same two nodes).
Actual Behavior
Only one KNOWS relationship between "Alice" and "Bob" exists in the database. The second graph.create(r2) call appears to overwrite the relationship created by graph.create(r1). The single remaining relationship will have the properties of r2 (i.e., since: 2021).
Verification via Cypher
The existence of only a single relationship can be verified with the following Cypher query, which will return only one relationship instead of the expected two:
MATCH (:Person {name: 'Alice'})-[r:KNOWS]->(:Person {name: 'Bob'})
RETURN r
In contrast, creating two relationships directly with Cypher demonstrates that Neo4j itself handles this correctly:
MATCH (a:Person {name: 'Alice'}), (b:Person {name: 'Bob'})
CREATE (a)-[:KNOWS {since: 2020}]->(b)
CREATE (a)-[:KNOWS {since: 2021}]->(b)
Running the verification query after these Cypher statements will correctly return two distinct relationships.
Suggested Workaround
To create multiple relationships of the same type between two nodes, a direct Cypher query using graph.run() should be used instead of graph.create() with py2neo.Relationship objects.
from py2neo import Graph, Node
graph = Graph("bolt://localhost:7687", auth=("neo4j", "password"))
a = Node("Person", name="Alice")
b = Node("Person", name="Bob")
graph.merge(a, "Person", "name")
graph.merge(b, "Person", "name")
# Use graph.run() with a CREATE Cypher query
graph.run(
"MATCH (a:Person {name: $a_name}), (b:Person {name: $b_name}) " +
"CREATE (a)-[:KNOWS {since: 2020}]->(b)",
a_name="Alice", b_name="Bob"
)
graph.run(
"MATCH (a:Person {name: $a_name}), (b:Person {name: $b_name}) " +
"CREATE (a)-[:KNOWS {since: 2021}]->(b)",
a_name="Alice", b_name="Bob"
)
Description
When creating multiple relationships of the same type between the same two nodes using
py2neo.Relationshipandgraph.create(), Neo4j unexpectedly overwrites the existing relationship instead of creating a new, distinct one. This behavior leads to data loss, as only the last created relationship is persisted. This appears to stem from howpy2neohandles relationship equality, which is based on the start node, end node, and relationship type. The officialpy2neodocumentation notes that this behavior differs from Neo4j itself, which permits multiple relationships of the same type between the same nodes.Reproduction
The following Python code demonstrates the issue:
Expected Behavior
Two distinct
KNOWSrelationships should exist between the "Alice" and "Bob" nodes, one with the propertysince: 2020and the other withsince: 2021. Neo4j inherently supports parallel relationships (i.e., multiple relationships of the same type between the same two nodes).Actual Behavior
Only one
KNOWSrelationship between "Alice" and "Bob" exists in the database. The secondgraph.create(r2)call appears to overwrite the relationship created bygraph.create(r1). The single remaining relationship will have the properties ofr2(i.e.,since: 2021).Verification via Cypher
The existence of only a single relationship can be verified with the following Cypher query, which will return only one relationship instead of the expected two:
In contrast, creating two relationships directly with Cypher demonstrates that Neo4j itself handles this correctly:
Running the verification query after these Cypher statements will correctly return two distinct relationships.
Suggested Workaround
To create multiple relationships of the same type between two nodes, a direct Cypher query using
graph.run()should be used instead ofgraph.create()withpy2neo.Relationshipobjects.