Upsert Edges using UpsertE
Create new edges or update existing ones with insert-or-update semantics.
UpsertE({properties})::From(node1)::To(node2)
UpsertE is a traversal step that operates on an existing traversal context. The type comes from the preceding traversal (E<Type>), not from the upsert call itself. If an edge already exists between the specified nodes, it is updated; if no edge is found, a new edge is created.
Edge connections (::From() and ::To()) are required for UpsertE. The order of From and To is flexible. Properties are also required.
Example 1: Basic edge upsert with properties
QUERY UpsertFriendship(id1: ID, id2: ID, since: String) =>
person1 <- N<Person>(id1)
person2 <- N<Person>(id2)
existing <- E<Knows>
edge <- existing::UpsertE({since: since})::From(person1)::To(person2)
RETURN edge
QUERY CreatePerson(name: String, age: U32) =>
person <- AddN<Person>({name: name, age: age})
RETURN person
Here’s how to run the query using the SDKs or curl
Python
Rust
Go
TypeScript
Curl
from helix.client import Client
client = Client( local = True , port = 6969 )
# Create two people
alice = client.query( "CreatePerson" , {
"name" : "Alice" ,
"age" : 25 ,
})[ 0 ][ "person" ]
bob = client.query( "CreatePerson" , {
"name" : "Bob" ,
"age" : 28 ,
})[ 0 ][ "person" ]
# First call creates the edge
result = client.query( "UpsertFriendship" , {
"id1" : alice[ "id" ],
"id2" : bob[ "id" ],
"since" : "2024-01-15" ,
})
print ( "Created edge:" , result)
# Subsequent calls update the existing edge (no duplicate created)
result = client.query( "UpsertFriendship" , {
"id1" : alice[ "id" ],
"id2" : bob[ "id" ],
"since" : "2024-06-20" ,
})
print ( "Upserted edge:" , result)
See all 32 lines
Example 2: Upsert edge with multiple properties
QUERY UpsertFriendshipWithProps(id1: ID, id2: ID, since: String, strength: F32) =>
person1 <- N<Person>(id1)
person2 <- N<Person>(id2)
existing <- E<Friendship>
edge <- existing::UpsertE({since: since, strength: strength})::From(person1)::To(person2)
RETURN edge
QUERY CreatePerson(name: String, age: U32) =>
person <- AddN<Person>({name: name, age: age})
RETURN person
Here’s how to run the query using the SDKs or curl
Python
Rust
Go
TypeScript
Curl
from helix.client import Client
client = Client( local = True , port = 6969 )
alice = client.query( "CreatePerson" , {
"name" : "Alice" ,
"age" : 25 ,
})[ 0 ][ "person" ]
bob = client.query( "CreatePerson" , {
"name" : "Bob" ,
"age" : 28 ,
})[ 0 ][ "person" ]
# Create friendship with properties
result = client.query( "UpsertFriendshipWithProps" , {
"id1" : alice[ "id" ],
"id2" : bob[ "id" ],
"since" : "2024-01-15" ,
"strength" : 0.85 ,
})
print ( "Created friendship:" , result)
# Update the friendship strength
result = client.query( "UpsertFriendshipWithProps" , {
"id1" : alice[ "id" ],
"id2" : bob[ "id" ],
"since" : "2024-01-15" ,
"strength" : 0.95 ,
})
print ( "Updated friendship:" , result)
See all 33 lines
Example 3: Flexible From/To ordering
The ::From() and ::To() can be specified in either order.
QUERY UpsertEdgeToFrom(id1: ID, id2: ID, since: String) =>
person1 <- N<Person>(id1)
person2 <- N<Person>(id2)
existing <- E<Knows>
// To and From can be in either order
edge <- existing::UpsertE({since: since})::To(person2)::From(person1)
RETURN edge
How Upsert differs from Add
Operation Behavior AddEAlways creates a new edge (can create duplicates) UpsertEOperates on traversal context: updates if edge exists between nodes, creates if not
When updating, UpsertE merges properties: it updates specified properties while preserving any existing properties that aren’t included in the upsert.