What is Helixir?
Helixir is a Rustlings-style tutorial for HelixDB. It is a collection of exercises that will help you learn how to create a simple hierarchical HelixDB database. After completing the tutorial, you will be able to translate the concepts in this guide to your own use cases.Getting Started
Installing HelixirInstall Helixir using the following command:
Install the HelixDB CLI using the following command:
Defining Nodes
We will be using HelixDB to model the relationships between continents, countries, and cities as a graph. First, we have to define what kind of entities/nodes will be in our graph. From the schema, we can see that we have 3 types of nodes: continents, countries, and cities. Node Definitions- The
Continent
node will have aname
property (String) - The
Country
node will have:name
(String),currency
(String),population
(U64), andgdp
(F64) - The
City
node will have:name
(String),description
(String), andzip_codes
(array of strings)
- Create a
Continent
,Country
, andCity
node with their respective properties inschema.hx
.
Answer
Answer
schema.hx
Defining Relationships
Now that we know what type of nodes are in our schema, we will define the relationships between those nodes. For this example, there is a hierarchical pattern where a city is in a country and a country is in a continent. Instructions:- Create a
Continent_to_Country
andCountry_to_City
edge connecting their respective nodes with no properties inschema.hx
.
Answer
Answer
schema.hx
Meta Relationships
In addition to the structural relationships between the nodes, you can also define relationships based on metadata. For example, a country must have a capital city. Instructions:- Create a
Country_to_Capital
edge connectingCountry
toCity
inschema.hx
.
Answer
Answer
schema.hx
Defining Vectors
Vectors in HelixDB allow us to create vector-based searches for semantic similarity. A vector is an array of floating-point numbers that represents the semantic meaning of data. In this case, we’ll create a vector for city descriptions to enable semantic search capabilities. Instructions:- Create a
CityDescription
vector withvector
property that takes an array ofF64
.
Answer
Answer
schema.hx
Basic Node Creation
Now that we have our schema, we need to write queries to insert the data. The best way to go about this given the structure of our data is to go from top (broad) to bottom (narrow) of the hierarchy. First, we will start with a basic query to create a continent. Usually, creation queries almost always include all the properties of the node in the arguments. In this case, we only need to know the continent’s name. Then we will useAddN
to add a Continent
node with property name
. For best practices, make sure to return the continent that was added in your query.
Instructions:
- Write a query to create a
Continent
node inqueries.hx
.
createContinent
name
: String
Answer
Answer
queries.hx
Relational Node Creation
Most of the nodes in our schema are related to other nodes, which means that we have to also create edges between them. However, we can optimize this process by creating both the node and the edge connecting it to other existing nodes in one query. In this exercise, we will create aCountry
node and connect it to its corresponding Continent
node. First we will first create a new Country
node using AddN
. Then we will get the Continent
node via the node’s ID so that we can create a Continent_to_Country
edge going from the created Continent
to Country
node using AddE
. We will also do the same thing for creating a City
node.
Instructions:
-
Write a query to create a
Country
node and connect it to its respectiveContinent
node by continent ID. -
Write a query to create a
City
node and connect it to its respectiveCountry
node by country ID.
createCountry
continent_id
: IDname
: Stringcurrency
: Stringpopulation
: I64gdp
: F64
createCity
country_id
: IDname
: Stringdescription
: String
Answer
Answer
queries.hx
Creating Meta Relationships
In order to add meta relationships into our graph, we will connect nodes together with the edges that define the meta relationships. For this example, we will create aCountry_to_Capital
edge from a Country
node to a City
node.
Instructions:
- Write a query to set a
City
node as the capital city of aCountry
node using their IDs.
setCapital
country_id
: IDcity_id
: ID
Answer
Answer
queries.hx
Creating Vector Embeddings
Vector embeddings allow us to perform similarity-based searches on our data. For city descriptions, this means we can find cities with similar characteristics even if they don’t share exact properties. We will create a vector embedding for each city’s description. Instructions: Write a query to create aCityDescription
vector and connect it to its respective City
node by city ID.
Query Parameters:
embedDescription
city_id
: IDvector
: [F64]
Answer
Answer
queries.hx
Get Nodes by ID
Now that we know how to create nodes and their relationships, we need to be able to retrieve nodes from our graph. The simplest way is to retrieve nodes when we know their ID. Instructions:- Write 3 queries to get
Continent
,Country
, andCity
by node ID.
getContinent
continent_id
: ID
getCountry
country_id
: ID
getCity
city_id
: ID
Answer
Answer
queries.hx
Get All Nodes of Type
In addition to retrieving nodes by ID, we often want to retrieve all nodes of a certain type. Since we have a hierarchical structure, we will also want to get all countries within a continent and all cities within a country. Instructions:-
Write 3 queries to get all
Continent
,Country
, andCity
nodes. -
Write 2 queries to get all
Country
andCity
nodes by their parent IDs.
getAllContinents
getAllCountries
getAllCities
getCountriesInContinent
continent_id
: ID
getCitiesInCountry
country_id
: ID
Answer
Answer
queries.hx
Get Nodes by Meta Relationship
Similar to getting nodes by their hierarchical relationships, we can also get nodes via their meta relationships. For this example, we will retrieve the capital city of a country. We’ll do this by traversing theCountry_to_Capital
edge from a Country
node to find its capital City
node.
Instructions:
- Write a query to get a country’s capital
City
node by the country’s ID.
getCapital
country_id
: ID
Answer
Answer
queries.hx
Get Node Properties
Sometimes we don’t need the full node, just a few specific properties. For example, we can display only the names and populations of countries without pulling in the entire node. In this case, we can use property selection syntax to retrieve just the fields we care about. This allows for more efficient querying and cleaner data handling when building visualizations or summaries. Instructions:- Write a query to get each country’s
name
andpopulation
.
getCountryNames
Answer
Answer
queries.hx
Get Nodes by Property
In addition to retrieving nodes by their ID or relationship, we often need to find nodes based on their properties. This allows for more flexible querying of our graph database. We will write queries to retrieve nodes by specific properties they contain. Instructions:- Write 3 queries that get the
Continent
,Country
, andCity
nodes by their names.
getContinentByName
continent_name
: String
getCountryByName
country_name
: String
getCityByName
city_name
: String
Answer
Answer
queries.hx
Get Nodes by Property Cont.
Building on property-based queries, you can also filter nodes using comparison operators. This allows you to find nodes that meet specific criteria rather than exact matches. You’ll practice with different comparison operators to filter countries by various attributes. Instructions:-
Write a query to get
Country
nodes by their currency. -
Write a query to get
Country
nodes with population less thanmax_population
. -
Write a query to get
Country
nodes with GDP greater than or equal tomin_gdp
.
getCountriesByCurrency
currency
: String
getCountriesByPopulation
max_population
: I64
getCountriesByGdp
min_gdp
: F64
Answer
Answer
queries.hx
Get Nodes by Many Properties
Now that we’ve seen how to get nodes by individual properties, we can also combine multiple conditions to perform more advanced filtering. For this example, we’ll write queries that retrieveCountry
nodes based on a combination of property values. This includes filtering countries with a population greater than a minimum and a GDP less than or equal to a maximum, as well as retrieving countries that either use a specific currency or have a population below a certain threshold. These types of queries allow us to refine our searches and extract more targeted subsets of data from our graph.
Instructions:
-
Write a query to find
Country
nodes with both population greater thanmin_population
and GDP less than or equal tomax_gdp
. -
Write a query to find
Country
nodes with either a specificcurrency
or a population less than or equal tomax_population
.
getCountriesByPopGdp
min_population
: I64max_gdp
: F64
getCitiesByCurrPop
currency
: Stringmax_population
: I64
Answer
Answer
queries.hx
Get Nodes by Meta Relationships
In addition to traversing structural relationships, we can also query nodes based on meta relationships. For example, we can retrieve allCountry
nodes that have a capital city assigned. This involves checking for the existence of an outgoing Country_to_Capital
edge from each Country
node. Meta relationship queries like this are useful for identifying nodes with specific contextual connections beyond hierarchical structures.
Instructions:
Write a query to get Country
nodes that have capital cities.
Query Parameters:
getCountriesWithCapitals
Answer
Answer
queries.hx
Get Range of Nodes
When working with large datasets, it’s often useful to limit the number of results returned from a query. TheRANGE
operator allows you to implement pagination and control result set size efficiently. This is particularly important for performance when dealing with queries that might return many nodes. The RANGE
operator takes two parameters: the starting index (0-based) and the number of items to return.
Instructions:
- Write a query to get the first
k
(I64
)City
nodes in a continent given the continent’s name.
getContinentCities
continent_name
: Stringk
: I64
Answer
Answer
queries.hx
Get Count of Nodes
In some cases, we want to gather basic statistics about our graph. For example, we can count the number of capital cities by checking how manyCity
nodes have an incoming Country_to_Capital
edge. Using the COUNT
operation, we can quickly compute aggregate statistics like this to better understand the structure and distribution of data across our graph.
Instructions:
- Write a query to get the number of capital cities.
countCapitals
Answer
Answer
queries.hx
Get Nodes with Anonymous Traversals
Sometimes we want to filter nodes based other node’s properties. For example, we can get all countries that have more than a certain number of cities. To do this, we’ll count the number of outgoingCountry_to_City
edges from each Country
node and filter by num_cities
. This pattern of anonymous traversal is useful when we care about the structure or degree of connectivity in the graph, rather than the specific linked nodes themselves.
Instructions:
- Write a query to get
Country
nodes that has more cities thannum_cities
.
getCountryByCityCnt
num_cities
: I64
Answer
Answer
queries.hx
Semantic Search Vectors
Semantic search allows us to go beyond exact matches by comparing the meaning of data. For example, we can find cities with similar descriptions using vector embeddings. By searching againstCityDescription
vectors, we can retrieve the top-k
most semantically similar City
nodes to a given input vector. This is especially useful when we want to find cities that share common characteristics or themes, even if their properties don’t match exactly.
For Helixir, we will be using fake embeddings to test the semantic search functionality. In real applications, you would use proper embeddings from providers like OpenAI, Gemini, etc.
- Write a query to semantically search a
vector
againstCityDescription
vectors and returning the topk
City
nodes.
searchDescriptions
vector
: [F64]k
: I64
Answer
Answer
queries.hx
Updating Nodes
Updating nodes allows us to modify the properties of existing entities in our graph without needing to recreate them. To update a node, we use theUPDATE
operation followed by the fields we want to modify. For example, we can update a country’s currency
by its ID
, or simultaneously update both its population
and GDP
. Keeping node data up-to-date ensures our graph remains accurate and relevant for queries, visualizations, and downstream analytics.
Instructions:
-
Write a query to update a country’s
currency
by a country’s ID. -
Write a query to update a country’s
population
andgdp
by a country’s ID.
updateCurrency
country_id
: IDcurrency
: String
updatePopGdp
country_id
: IDpopulation
: I64gdp
: F64
Answer
Answer
queries.hx
Deleting Nodes
Deleting nodes is useful when we want to clean up outdated or incorrect data from our graph. However, this can get tricky in a graph database because not only do we have to drop the node but also the relationships connected to that node. Additionally, the order in which we drop them is very important. For example, if a city is no longer relevant or a country needs to be removed entirely, we can drop the node and its relationship to the country as a city and also potentially as a capital city. In cases where the node is linked through specific edges, like a capital city connection, it’s important to remove those edges first to maintain the graph structure and allowing us to drop the other edges later. This ensures that dependent edges don’t linger in the system, avoiding potential inconsistencies during traversal or analytics. Instructions:-
Write a query to delete a
City
node given its ID. -
Write a query to delete a capital
City
node given its country’s ID. -
Write a query to delete a
Country
node given its ID.
deleteCity
city_id
: ID
deleteCapital
country_id
: ID
deleteCountry
country_id
: ID
Answer
Answer
queries.hx
Updating Meta Relationships
Sometimes you need to update the meta relationships between nodes rather than creating new ones. For example, you might want to change which city serves as a country’s capital. This involves removing the existing capital relationship and creating a new one with a different city. When updating meta relationships, it’s important to properly manage the edge connections to maintain graph consistency. Instructions:- Write a query to update the capital
City
node of aCoutry
node given the country’s ID and the new capital city’s ID.
updateCapital
country_id
: IDcity_id
: ID
Answer
Answer
queries.hx
Updating Embeddings
When working with vector embeddings, you often need to update both the node properties and their associated vector embeddings. For example, when a city’s description changes, you need to update the description property and also update the corresponding vector embedding to reflect the new semantic meaning. This ensures that semantic searches remain accurate and relevant. Instructions:- Write a query to update the
description
of aCity
node given its ID and also update theCityDescription
vector embedding given a newvector
.
updateDescription
city_id
: IDdescription
: Stringvector
: [F64]
Answer
Answer
queries.hx
Congratulations!
You’ve completed the Helixir guide!
In this guide, we covered the basics of querying a graph database using Helixir. We learned how to create nodes, relationships, and properties. We also learned how to filter, update, and delete nodes and their relationships. This is just the beginning of what you can do with Helixir. There are many more features and capabilities that you can explore. If you have any questions or feedback, please feel free to reach out to us!Next Steps
Skip the Infrastructure HassleGoing from local testing to production? Helix Cloud makes it effortless. We handle servers, scaling, and maintenance so you can focus on building your application. Explore Use Cases
Ready to dive deeper? Check out our guides and tutorials for real-wold use cases and advanced scenarios. Learn the Language
Get to know HelixQL, our fast, efficient query language built for traversing and manipulating graph and vector data. Work with the SDK
Build, query, and embed entirely in your language of choice using our Python SDK, TypeScript SDK, Rust SDK, and Go SDK. Unlock More Features
Discover everything HelixDB has to offer with our cutting-edge features.