IndexedDB)complete
VALUE
clauses can be used to ensure a default value is always specified if no data is entered.$before
and $after
value of the record, enabling advanced custom logic with each trigger.UNIQUE
values in a table. Table indexes can be specified for a column, multiple columns, and have support for all nested fields including arrays and objects.-- Specify a field on the user table
DEFINE FIELD email ON TABLE user TYPE string ASSERT string::is::email($value);
-- Add a unique index on the email field to prevent duplicate values
DEFINE INDEX email ON TABLE user COLUMNS email UNIQUE;
-- Create a new event whenever a user changes their email address
DEFINE EVENT email ON TABLE user WHEN $before.email != $after.email THEN (
CREATE event SET user = $this, time = time::now(), value = $after.email, action = 'email_changed'
);
ASSERT
clause which acts as a constraint on the data. This clause enables advanced SurrealQL statements which can ensure that the $value
entered is within certain parameters. Each clause is also able to see the $before
and $after
value of the record, enabling advanced custom logic with each trigger.-- Specify a field on the user table
DEFINE FIELD countrycode ON user TYPE string
-- Ensure country code is ISO-3166
ASSERT $value = /[A-Z]{3}/
-- Set a default value if empty
VALUE $value OR $before OR 'GBR'
;
-- Define a text analyzer
DEFINE ANALYZER en TOKENIZERS camel,class FILTERS snowball(English);
-- Define a search index for a field on the book table
DEFINE INDEX search_title ON book COLUMNS title SEARCH ANALYZER en BM25 HIGHLIGHTS;
-- Select all books who match given keywords
SELECT search::score(1) AS score, search::highlight('<b>', '</b>', 1) AS title
FROM book WHERE title @1@ 'rust web' ORDER BY score DESC;
euclidean
distance metrics. Vector embeddings can be used for similarity matching, and for advanced data analysis.-- Add vector embedding data to record content
CREATE article:1 SET embedding = [1, 2, 3, 4];
CREATE article:2 SET embedding = [4, 5, 6, 7];
CREATE article:3 SET embedding = [8, 9, 10, 11];
-- Define a vector embedding index for a field on the article table
DEFINE INDEX mt_obj ON vec FIELDS embedding MTREE DIMENSION 4 DIST EUCLIDEAN;
-- Drop all writes to the reading table. We don't need every reading.
DEFINE TABLE reading DROP;
-- Define a table as a view which aggregates data from the reading table
DEFINE TABLE temperatures_by_month AS
SELECT
count() AS total,
time::month(recorded_at) AS month,
math::mean(temperature) AS average_temp
FROM reading
GROUP BY city
;
-- Add a new temperature reading with some basic attributes
CREATE reading SET
temperature = 27.4,
recorded_at = time::now(),
city = 'London',
location = (-0.118092, 51.509865)
;
-- Subscribe to all matching document changes
LIVE SELECT * FROM document
WHERE
account = $auth.account
OR public = true
;
-- Subscribe to all changes to a single record
LIVE SELECT * FROM post:c569rth77ad48tc6s3ig;
-- Stop receiving change notifications
KILL "1986cc4e-340a-467d-9290-de81583267a2";
-- Define a global parameter which will be accessible to all queries.
DEFINE PARAM $STRIPE VALUE "https://api.stripe.com/payments/new";
-- Use the defined global parameter in all queries on the database.
DEFINE EVENT payment ON TABLE order WHEN $event = 'CREATE' THEN http::post($STRIPE, $value);
decimal
based numbers, but can be stored as int
or float
values for 64 bit integer or 64 bit floating point precision.NONE
, or NULL
. A field which is NONE
does not have any data stored, while NULL
values are values which are entered but empty.Point
, Line
, Polygon
, MultiPoint
, MultiLine
, MultiPolygon
, and Collection
values. SurrealQL automatically detects GeoJSON objects converting them into a single data type.UPDATE city:london SET
centre = (-0.118092, 51.509865),
boundary = {
type: "Polygon",
coordinates: [[
[-0.38314819, 51.37692386], [0.1785278, 51.37692386],
[0.1785278, 51.61460570], [-0.38314819, 51.61460570],
[-0.38314819, 51.37692386]
]]
}
;
SELECT
clause.UPDATE product SET
name = "SurrealDB",
launch_at = <datetime> "2021-11-01",
countdown = <future> { launch_at - time::now() }
;
bool
, int
, float
, string
, number
, decimal
, datetime
, and duration
casts.UPDATE person SET
waist = <int> "34",
height = <float> 201,
score = <decimal> 0.3 + 0.3 + 0.3 + 0.1
;
// Ensure that a record field must be a number.
DEFINE FIELD age ON person TYPE number;
// Allow the field to be optional or a number.
DEFINE FIELD age ON person TYPE option<number>;
// Ensure that a record link is specified and of a specific type.
DEFINE FIELD author ON book TYPE record<person>;
// Allow a field to be optional and of a selection of types.
DEFINE FIELD pet ON user TYPE option<record<cat | dog>>;
// Allow a field to be one of multiple types.
DEFINE FIELD rating ON film TYPE float | decimal;
// Ensure that a field is an a array of unique values of a certain length.
DEFINE FIELD tags ON person TYPE set<string, 5>;
SELECT
, CREATE
, UPDATE
, and DELETE
methods. These enable selecting or modifying individual records, or whole tables. Each statement supports multiple different tables or record types at once.-- Create a new article record with a specific id
CREATE article:surreal SET name = "SurrealDB: The next generation database";
-- Update the article record, and add a new field
UPDATE article:surreal SET time.created = time::now();
-- Select all matching articles
SELECT * FROM article, post WHERE name CONTAINS 'SurrealDB';
-- Delete the article
DELETE article:surreal;
RELATE
statement adds graph edges between records in SurrealDB. It follows the convention of vertex -> edge -> vertex
or noun -> verb -> noun
, enabling the addition of metadata to the edge record.-- Add a graph edge between user:tobie and article:surreal
RELATE user:tobie->write->article:surreal
SET time.written = time::now()
;
-- Add a graph edge between specific users and developers
LET $from = (SELECT users FROM company:surrealdb);
LET $devs = (SELECT * FROM user WHERE tags CONTAINS 'developer');
RELATE $from->like->$devs UNIQUE
SET time.connected = time::now()
;
INSERT
statement resembles the traditional SQL statement, enabling users to get started quickly. It supports the creation of records using a VALUES
clause, or by specifying the record data as an object.INSERT INTO company {
name: 'SurrealDB',
founded: "2021-09-10",
founders: [person:tobie, person:jaime],
tags: ['big data', 'database']
};
INSERT IGNORE INTO company (name, founded)
VALUES ('SurrealDB', '2021-09-10')
ON DUPLICATE KEY UPDATE tags += 'developer tools'
;
FOR
statements enable simplified iteration over data, or for advanced logic when dealing with nested arrays or recursive functions, within code blocks or custom functions.FOR $person IN (SELECT VALUE id FROM person) {
CREATE gift CONTENT {
recipient: $person,
type: "ticket",
date: time::now(),
event: "SurrealDB World",
};
};
THROW
statement statement can be used to return custom error types, which allow for building advanced programming and business logic right within the database and authentication engine.FOR $user IN $input {
IF $user.age < 18 {
THROW "Only adults should be inserted";
}
IF $user.country != 'USA' {
THROW $user.country + " is not a valid country";
}
};
.
, or array notation []
.-- Use mathematical operators to calculate value
SELECT * FROM temperature WHERE (celsius * 1.8) + 32 > 86.0;
-- Use geospatial operator to detect polygon containment
SELECT * FROM restaurant WHERE location INSIDE {
type: "Polygon",
coordinates: [[
[-0.38314819, 51.37692386], [0.1785278, 51.37692386],
[0.1785278, 51.61460570], [-0.38314819, 51.61460570],
[-0.38314819, 51.37692386]
]]
};
-- Select all people whose tags contain "tag1" OR "tag2"
SELECT * FROM person WHERE tags CONTAINSANY ["tag1", "tag2"];
-- Select all people who have any email address ending in 'gmail.com'
SELECT * FROM person WHERE emails.*.value ?= /gmail.com$/;
math::E
, math::FRAC_1_PI
, math::FRAC_1_SQRT_2
, math::FRAC_2_PI
, math::FRAC_2_SQRT_PI
, math::FRAC_PI_2
, math::FRAC_PI_3
, math::FRAC_PI_4
, math::FRAC_PI_6
, math::FRAC_PI_8
, math::LN_10
, math::LN_2
, math::LOG10_2
, math::LOG10_E
, math::LOG2_10
, math::LOG2_E
, math::PI
, math::SQRT_2
, and math::TAU
..
, array notation []
, and graph semantics ->
. SurrealQL enables records to link to other records and traverses all embedded links or graph connections as desired. When traversing and fetching remote records SurrealQL enables advanced filtering using traditional WHERE
clauses.-- Select a nested array, and filter based on an attribute
SELECT emails[WHERE active = true] FROM person;
-- Select all 1st, 2nd, and 3rd level people who this specific person record knows, or likes, as separate outputs
SELECT ->knows->(? AS f1)->knows->(? AS f2)->(knows, likes WHERE influencer = true AS e3)->(? AS f3) FROM person:tobie;
-- Select all person records (and their recipients), who have sent more than 5 emails
SELECT *, ->sent->email->to->person FROM person WHERE count(->sent->email) > 5;
-- Select other products purchased by people who purchased this laptop
SELECT <-purchased<-person->purchased->product FROM product:laptop;
-- Select products purchased by people in the last 3 weeks who have purchased the same products that we purchased
SELECT ->purchased->product<-purchased<-person->(purchased WHERE created_at > time::now() - 3w)->product FROM person:tobie;
// Set a new parameter
LET $now = time::now();
// Create a record with a complex ID using an array
CREATE temperature:['London', $now] SET
location = 'London',
date = $now,
temperature = 23.7
;
// Create a record with a complex ID using an object
CREATE temperature:{ location: 'London', date: $now } SET
location = 'London',
date = $now,
temperature = 23.7
;
-- Select all person records with IDs between the given range
SELECT * FROM person:1..1000;
-- Select all records for a particular location, inclusive
SELECT * FROM temperature:['London', NONE]..=['London', time::now()];
-- Select all temperature records with IDs less than a maximum value
SELECT * FROM temperature:..['London', '2022-08-29T08:09:31'];
-- Select all temperature records with IDs greater than a minimum value
SELECT * FROM temperature:['London', '2022-08-29T08:03:39']..;
-- Select all temperature records with IDs between the specified range
SELECT * FROM temperature:['London', '2022-08-29T08:03:39']..['London', '2022-08-29T08:09:31'];
.surml
data-format, enabling the model to be run consistently and safely in Python, Rust, or SurrealDB. Models can then be imorted into SurrealDB, allowing for Inference directly against any data in the database.from surrealml import SurMlFile
# Specify the trained model, model name, and model inputs
file = SurMlFile(model=model, name="house::price::prediction", inputs=test_inputs)
# Add a description for this model that can be viewed in teh database
file.add_description("This model predicts the price of a house based on its square footage and number of floors.")
# Add a version identifier which enables specific model versions to be run separately
file.add_version("0.3.0")
# Optionally define named input fields and data normalisation functions
file.add_column("squarefoot")
file.add_column("num_floors")
file.add_normaliser("squarefoot", "z_score", squarefoot_mean, squarefoot_std)
file.add_normaliser("num_floors", "z_score", num_floors_mean, num_floors_std)
# Optionally specify named output fields with normalisation functions
file.add_output("house_price", "z_score", house_price_mean, house_price_std)
# Save the .surml file, ready to execute or import into the database
file.save("./my_model.surml")
.surml
model files in Python allows for consistent and reproducible modeel computation in development, continuous integration, testing, or production environments.from surrealml import SurMlFile
# Load the model file from disk
model = SurMlFile.load("./my_model.surml")
# Perform raw vector compute against the model
output = model.raw_compute([1.0, 2.0], [1, 2])
# Perform named buffered compute against the model
output = model.buffered_compute({
"squarefoot": 3200.0,
"num_floors": 2.0
})
-- Perform raw computation against the imported model
RETURN ml::house::price::prediction<0.3.0>(
[1.0, 2.0], [1, 2]
);
-- Perform named buffered computation against the imported model
SELECT
*,
ml::house::price::prediction<0.3.0>({
squarefoot: squarefoot_col,
num_floors: num_floors_col
}) AS price_prediction
FROM property_listing
WHERE price_prediction > 177206.21875
;
SELECT * FROM geo::hash::encode( (-0.118092, 51.509865) );
SELECT time::floor(created_at, 1w) FROM user;
SELECT count(age > 18) FROM user GROUP ALL;
SELECT email, string::is::email(email) AS valid FROM user;
this
value.CREATE film SET
ratings = [
{ rating: 6, user: user:bt8e39uh1ouhfm8ko8s0 },
{ rating: 8, user: user:bsilfhu88j04rgs0ga70 },
],
featured = function() {
return this.ratings.filter(r => {
return r.rating >= 7;
}).map(r => {
return { ...r, rating: r.rating * 10 };
});
}
;
-- Define a global function which can be used in any query
DEFINE FUNCTION fn::get::person($first: string, $last: string, $birthday: string) {
LET $person = SELECT * FROM person WHERE [first, last, birthday] = [$first, $last, $birthday];
RETURN IF $person[0].id THEN
$person[0]
ELSE
CREATE person SET first = $first, last = $last, birthday = $birthday
END;
};
-- Call the global custom function, receiving the returned result
LET $person = fn::get::person('Tobie', 'Morgan Hitchcock', '2022-09-21');
IPv4
or IPv6
IP addresses.ES256
, ES384
, ES512
, HS256
, HS384
, HS512
, PS256
, PS384
, PS512
, RS256
, RS384
, and RS512
algorithms are supported.-- Enable scope authentication directly in SurrealDB
DEFINE SCOPE account SESSION 24h
SIGNUP ( CREATE user SET email = $email, pass = crypto::argon2::generate($pass) )
SIGNIN ( SELECT * FROM user WHERE email = $email AND crypto::argon2::compare(pass, $pass) )
;
// Signin and retrieve a JSON Web Token
let jwt = fetch('https://api.surrealdb.com/signup', {
method: 'POST',
headers: {
Accept: 'application/json',
NS: 'google', // Specify the namespace
DB: 'gmail', // Specify the database
},
body: JSON.stringify({
NS: 'google',
DB: 'gmail',
SC: 'account',
email: 'tobie@surrealdb.com',
pass: 'a85b19*1@jnta0$b&!',
}),
});
-- Specify access permissions for the 'post' table
DEFINE TABLE post SCHEMALESS
PERMISSIONS
FOR select
-- Published posts can be selected
WHERE published = true
-- A user can select all their own posts
OR user = $auth.id
FOR create, update
-- A user can create or update their own posts
WHERE user = $auth.id
FOR delete
-- A user can delete their own posts
WHERE user = $auth.id
-- Or an admin can delete any posts
OR $auth.admin = true
;
## Execute a SurrealQL query
localhost % curl -X POST https://api.surrealdb.com/sql
## Interact with a table
localhost % curl -X GET https://api.surrealdb.com/key/user
localhost % curl -X POST https://api.surrealdb.com/key/user
localhost % curl -X DELETE https://api.surrealdb.com/key/user
## Interact with a record
localhost % curl -X GET https://api.surrealdb.com/key/user/tobie
localhost % curl -X PUT https://api.surrealdb.com/key/user/tobie
localhost % curl -X POST https://api.surrealdb.com/key/user/tobie
localhost % curl -X PATCH https://api.surrealdb.com/key/user/tobie
localhost % curl -X DELETE https://api.surrealdb.com/key/user/tobie
user@localhost % surreal
.d8888b. 888 8888888b. 888888b.
d88P Y88b 888 888 'Y88b 888 '88b
Y88b. 888 888 888 888 .88P
'Y888b. 888 888 888d888 888d888 .d88b. 8888b. 888 888 888 8888888K.
'Y88b. 888 888 888P' 888P' d8P Y8b '88b 888 888 888 888 'Y88b
'888 888 888 888 888 88888888 .d888888 888 888 888 888 888
Y88b d88P Y88b 888 888 888 Y8b. 888 888 888 888 .d88P 888 d88P
'Y8888P' 'Y88888 888 888 'Y8888 'Y888888 888 8888888P' 8888888P'
To get started using SurrealDB, and for guides on connecting to and building applications
on top of SurrealDB, check out the SurrealDB documentation (https://surrealdb.com/docs/).
If you have questions or ideas, join the SurrealDB community (https://surrealdb.com/community).
If you find a bug, submit an issue on GitHub (https://github.com/surrealdb/surrealdb/issues).
We would love it if you could star the repository (https://github.com/surrealdb/surrealdb).
----------
Usage: surreal <COMMAND>
Commands:
start Start the database server
backup Backup data to or from an existing database
import Import a SurrealQL script into an existing database
export Export an existing database as a SurrealQL script
version Output the command-line tool and remote server version information
upgrade Upgrade to the latest stable version
sql Start an SQL REPL in your terminal with pipe support
is-ready Check if the SurrealDB server is ready to accept connections [aliases: isready]
validate Validate SurrealQL query files
help Print this message or the help of the given subcommand(s)
Options:
-h, --help Print help
docker run --rm --pull always -p 8000:8000 surrealdb/surrealdb:latest start