Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.helix-db.com/llms.txt

Use this file to discover all available pages before exploring further.

HelixQL is deprecated in HelixDB v2. Queries are now written with the Rust DSL and dispatched as JSON — see the Querying guide. This section is kept as a reference for legacy HelixQL projects.
For the complete documentation index optimized for AI agents, see llms.txt.

Upsert Vectors using UpsertV  

Create new vector embeddings or update existing ones with insert-or-update semantics.
::UpsertV(vector, {properties})
UpsertV is a traversal step that operates on an existing traversal context. The type comes from the preceding traversal (V<Type>), not from the upsert call itself. If the traversal returns existing vectors, they are updated; if no vectors are found, a new vector is created.
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) =>
    existing <- V<Document>::WHERE(_::{content}::EQ(content))
    doc <- existing::UpsertV(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) =>
    existing <- V<Document>::WHERE(_::{content}::EQ(text))
    doc <- existing::UpsertV(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
) =>
    existing_person <- N<Person>::WHERE(_::{name}::EQ(person_name))
    person <- existing_person::UpsertN({name: person_name, age: person_age})
    existing_company <- N<Company>::WHERE(_::{name}::EQ(company_name))
    company <- existing_company::UpsertN({name: company_name})
    existing_edge <- E<WorksAt>
    edge <- existing_edge::UpsertE({position: position})::From(person)::To(company)
    existing_resume <- V<Resume>::WHERE(_::{content}::EQ(resume_content))
    resume <- existing_resume::UpsertV(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
UpsertVOperates on traversal context: updates if vectors found, creates if empty
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.