Skip to main content

Upsert Vectors using UpsertV  

Create new vector embeddings or update existing ones with insert-or-update semantics.
UpsertV<Type>(vector)
UpsertV<Type>(vector, {properties})
UpsertV differs from AddV in that it will update an existing vector if one is found in the traversal context, rather than always creating a new one. If no existing vector is found, it creates a new vector just like AddV.
Vector data is required for UpsertV. You can provide vector data as:
  • A literal array of floats (e.g., [0.1, 0.2, 0.3])
  • The Embed() function to generate embeddings from text
  • A variable containing vector data

Example 1: Basic vector upsert with properties

QUERY UpsertDoc(vector: [F64], content: String) =>
    doc <- UpsertV<Document>(vector, {content: content})
    RETURN doc
Here’s how to run the query using the SDKs or curl
from helix.client import Client

client = Client(local=True, port=6969)

# First call creates a new document
doc = client.query("UpsertDoc", {
    "vector": [0.1, 0.2, 0.3, 0.4],
    "content": "Introduction to machine learning",
})

print("Created document:", doc)

# Subsequent calls with same vector update the existing document
updated = client.query("UpsertDoc", {
    "vector": [0.1, 0.2, 0.3, 0.4],
    "content": "Updated introduction to machine learning",
})

print("Updated document:", updated)

Example 2: Upsert vector using the Embed function

You can use the built-in Embed function to generate embeddings from text.
All vectors in a vector type must have the same dimensions. If you change your embedding model, the new vectors will have different dimensions and will cause an error. Ensure you use the same embedding model consistently for all vectors.
QUERY UpsertDocEmbed(text: String) =>
    doc <- UpsertV<Document>(Embed(text), {content: text})
    RETURN doc
Here’s how to run the query using the SDKs or curl
from helix.client import Client

client = Client(local=True, port=6969)

# Upsert with automatic embedding generation
doc = client.query("UpsertDocEmbed", {
    "text": "Introduction to machine learning",
})

print("Upserted document:", doc)

Example 3: Complex operation with nodes, edges, and vectors

QUERY ComplexUpsertOperation(
    person_name: String,
    person_age: U32,
    company_name: String,
    position: String,
    resume_content: String
) =>
    person <- UpsertN<Person>({name: person_name, age: person_age})
    company <- UpsertN<Company>({name: company_name})
    UpsertE<WorksAt>({position: position})::From(person)::To(company)
    resume <- UpsertV<Resume>(Embed(resume_content), {content: resume_content})
    RETURN person

QUERY GetPerson(name: String) =>
    person <- N<Person>::WHERE(_::{name}::EQ(name))
    RETURN person
Here’s how to run the query using the SDKs or curl
from helix.client import Client

client = Client(local=True, port=6969)

# Create or update person, company, employment, and resume all at once
result = client.query("ComplexUpsertOperation", {
    "person_name": "Alice",
    "person_age": 30,
    "company_name": "TechCorp",
    "position": "Software Engineer",
    "resume_content": "Experienced software engineer with 5 years...",
})

print("Upserted person:", result)

# Running again will update existing records instead of creating duplicates
result = client.query("ComplexUpsertOperation", {
    "person_name": "Alice",
    "person_age": 31,  # Updated age
    "company_name": "TechCorp",
    "position": "Senior Software Engineer",  # Updated position
    "resume_content": "Experienced senior software engineer with 6 years...",
})

print("Updated person:", result)

How Upsert differs from Add

OperationBehavior
AddVAlways creates a new vector
UpsertVCreates if not exists, updates if exists
When updating, UpsertV merges properties: it updates specified properties while preserving any existing properties that aren’t included in the upsert. The vector data itself is also updated.