Exploring SurrealDB: The Next Generation Serverless Database Solution

Exploring SurrealDB: The Next Generation Serverless Database Solution

What is SurrealDB:

SurrealDB is an open-source NewSQL that simplifies the database and API stack, making it easier and faster to develop secure and performant applications. Written in Rust, this cloud-native database solution is considered the next-generation serverless database with support for structured and unstructured data, graph querying, full-text indexing, geospatial querying, and permissions-based access control.

SurrealDB stands out from other databases due to its wide range of features. It boasts a plethora of impressive capabilities such as sophisticated inter-document relationships and analysis, straightforward schema definition for both frontend and backend development, and the ability to execute real-time live queries and observe data changes directly in the application. In this article, we will explore some of these features and highlight what makes them particularly noteworthy.

SurrealDB: A Myriad of Features

Despite being in the development phase, SurrealDB already offers numerous features and plugins, with even more expected in future releases. The most recent update, version v1.0.0-beta.9, is available on GitHub and includes various improvements and bug fixes.

To avoid making this article excessively long, we won't be able to discuss all of SurrealDB's features. Nevertheless, we'd like to highlight a few features that we think you'll find particularly interesting:

Schemafull or schemaless:

Traditional databases like MySQL, PostgreSQL and OracleDB, require predefined schemas. These databases enforce a strict structure for the data, and any data that is inserted must adhere to the predefined schema.

SurrealDB can, however, take both databases that are structured or unstructured, making it more flexible, and allowing users to choose which approach works best for their needs.

By default, SurrealDB creates a schemaless table. To create a typical table with structure, you can use the DEFINE TABLE function. For example, to create a "student" table with a "name" and “age” field, you can run the following code:

DEFINE TABLE student Schemafull; 
-- Specifing a field on the article table 
DEFINE FIELD name ON TABLE student Type string; 
DEFINE FIELD age ON TABLE student Type int; 
-- Creating the article table 
CREATE student:101 SET name = 'james', age = 15;

With these queries, you create a structured student table with ID 101 that stores data in a defined format, rather than as a free-form collection of data. This can help with organizing and querying your data more efficiently.

SurrealSQL

Notice how in our previous query, the query looks like a typical SQL query. SurrealDB uses a query language called SurrealSQL, which is similar to SQL. This makes it easy for developers familiar with SQL to work with SurrealDB. The SurrealSQL language supports creating, selecting, deleting, and other common database operations. Here is an example of a SurrealSQL query:

-- Insert some data 
CREATE user:1 SET name = 'Alice', age = 25; 
CREATE user:2 SET name = 'Bob', age = 30; 

-- Update a record 
UPDATE user:1 SET age = 27; 

-- Select records with a where condition 
SELECT * FROM users WHERE age > 25; 

-- Delete a record
DELETE user:2;

This query inserts two records in the user table with ID 1 and 2. It then updates the age of the record with ID 1 to 27, selects all records where the age field is greater than 25, and finally deletes the record with ID 2.

Elimination of Joins

In SurrealDB, each record is assigned a unique record ID when it is created. This ID can be specified explicitly or generated automatically by the system. Using these record IDs, it is possible to fetch data from different tables without having to use joins, which can make queries more concise and less complicated.

Unlike traditional SQL databases, where data is often spread across multiple tables that are joined together to retrieve related data, SurrealDB uses record links to connect related data. This means that data from different tables can be fetched together without the need for joins, which can be a major advantage when dealing with complex data structures. Here is an example:

The following code creates two records, one for each user, and then creates two car records, each linked to one of the users:

-- Create two users records 
CREATE user:john SET first_name = "John", age = 27; 
CREATE user:Peter SET Firts_name = "Peter" age = 32; 

-- Create two car records, each linked to a user record 
CREATE Car:Honda SET model = "C-classic", owner = user:john; 
CREATE Car:Toyota SET model = "G-classic", Owner = user:Peter;

Notice how the owner field in the car record is linked to the ID of the corresponding user record using the syntax owner = user:John. This establishes a relationship between the car and user records that allow us to fetch data from both tables at once.

To retrieve data from the car table along with the corresponding user record, we can use the FETCH statement in a SELECT query:

 -- Select all car records and fetch the corresponding user record 
SELECT * FROM car FETCH user;

This query would output all the data in the car table, along with the corresponding user record for each post.

Graph Connections

In the previous example, we saw how SurrealDB eliminates the need for joins by using record links. However, this approach only allowed us to pull user data from the car table. It becomes challenging to pull post data from the user's table using this one-way connection. SurrealDB provides a solution to achieve this with its RELATE statement.

The RELATE statement creates edges between two records in the database, enabling easy access to related data.

Following our previous example, suppose each user painted a car with different colours and we want to show what user painted what car. Here's an example query using the RELATE statement:

RELATE user:john -> painted -> car:Honda CONTENT { colour: 'Red' }; 
RELATE user:peter -> painted -> car:Toyota CONTENT { Colour: 'Yellow' };

In this example, we're using the RELATE statement to create graph edges between the car and user tables, relating each painted car to a user. The query basically shows that user:John painted the Honda car red and user:Peter painted the Toyota car yellow. Here is what it would look like to pull data from either of the tables:

-- Pulling the painted car data from the user table 
SELECT id,->painted -> car FROM user; 

-- Pulling the painted car data from the car table 
SELECT id,<- painted <- user FROM car;

The first query shows the users and the car they painted, the second showed what cars were painted by what users.

Note that the arrow direction in the SELECT statement specifies the direction of the relationship we want to traverse. The -> arrow direction means we want to traverse the relationship from left to right, while <- means we want to traverse from right to left.

As previously mentioned, SurrealDB has a plethora of features available for use. To discover more, it is recommended to refer to the documentation. Some other features currently in development include live queries and record changes, versioned temporal tables, full-text indexing and filtering, and various others.

To get started with SurrealDB, you can watch the Fireships video on youtube:

In our next article, we'll explore How to Integrate SurrealDB with DenoJS, a modern and secure runtime for JavaScript and TypeScript. Stay tuned for an in-depth tutorial on how to leverage these two powerful tools together to build robust and scalable applications.