From 223c070927352455495b3c72ed847d575df11d7a Mon Sep 17 00:00:00 2001 From: Dave MacLeod <56599343+Dhghomon@users.noreply.github.com> Date: Tue, 24 Dec 2024 14:01:44 +0900 Subject: [PATCH 01/15] Start some content on references --- .../doc-surrealql/datamodel/records.mdx | 2 +- .../doc-surrealql/datamodel/references.mdx | 117 ++++++++++++++++++ src/content/doc-surrealql/datamodel/sets.mdx | 2 +- .../doc-surrealql/datamodel/strings.mdx | 2 +- src/content/doc-surrealql/datamodel/uuid.mdx | 2 +- .../doc-surrealql/datamodel/values.mdx | 2 +- .../doc-surrealql/statements/define/field.mdx | 17 +++ 7 files changed, 139 insertions(+), 5 deletions(-) create mode 100644 src/content/doc-surrealql/datamodel/references.mdx diff --git a/src/content/doc-surrealql/datamodel/records.mdx b/src/content/doc-surrealql/datamodel/records.mdx index d6bf410ba..50c768550 100644 --- a/src/content/doc-surrealql/datamodel/records.mdx +++ b/src/content/doc-surrealql/datamodel/records.mdx @@ -90,7 +90,7 @@ SELECT friends.friends.friends.name FROM person:tobie; You've now seen how to create records using randomly generated ids, or specific record ids. This is just the beginning! The power and flexibility which is possible with the remote record fetching functionality within queries opens up a whole new set of possibilities for storing and querying traditional data, and connected datasets. Take a look at the next chapter to understand how futures can be used to dynamically compute values only when retrieved. -Also checkout this explainer video on using record links in SurrealDB: +Also check out this explainer video on using record links in SurrealDB:
diff --git a/src/content/doc-surrealql/datamodel/references.mdx b/src/content/doc-surrealql/datamodel/references.mdx new file mode 100644 index 000000000..11b98345d --- /dev/null +++ b/src/content/doc-surrealql/datamodel/references.mdx @@ -0,0 +1,117 @@ +--- +sidebar_position: 17 +sidebar_label: Record references +title: Record references | SurrealQL +description: One of the most powerful features of SurrealDB is the ability to traverse from record-to-record without the need for traditional SQL JOINs. Each record ID points directly to a specific record in the database. + +--- + +import Since from '@components/shared/Since.astro' + +# Record references + + + +## Basic concepts + +Reference tracking begins by adding a `REFERENCE` clause to any `DEFINE FIELD` statement, as long as the field is a `record` or array of records. + +```surql +DEFINE FIELD comics ON person TYPE option>> REFERENCE; +``` + +Any referencing record can then be picked up on the referenced record by creating a field of type `references`. + +```surql +DEFINE FIELD owners ON comic_book TYPE references; +``` + +```surql +CREATE person:one, person:two SET comics = [comic_book:one]; +CREATE comic_book:one SET title = "Loki, God of Stories"; +SELECT * FROM comic_book; +``` + +The linking records will now be picked up automatically from the `comic_book` side. + +```surql title="Output" +[ + { + id: comic_book:one, + owners: [ + person:one, + person:two + ], + title: 'Loki, God of Stories' + } +] +``` + +## Specifying linking tables + +The following is similar to the previous example, except that the `comic_book` is now being linked to from two sources, one of which is a `publisher` which publishes both books and comic books. + +```surql +DEFINE FIELD comics ON person TYPE option>> REFERENCE; +DEFINE FIELD products ON publisher TYPE option>> REFERENCE; +DEFINE FIELD owners ON comic_book TYPE references; + +CREATE person:one, person:two SET comics = [comic_book:one]; +CREATE publisher:one SET products = [comic_book:one, book:one]; +CREATE comic_book:one SET title = "Loki, God of Stories"; +SELECT * FROM comic_book; +``` + +Because the `owners` field on `comic_book` looks for any and all references, it now includes the publisher as an owner, which is not ideal. + +```surql title="Output" +[ + { + id: comic_book:one, + owners: [ + person:one, + person:two, + publisher:one + ], + title: 'Loki, God of Stories' + } +] +``` + +This can be fixed by changing the single field of type `references` to two fields, one of which is a `references`, and the other a `references`. + +```surql +REMOVE TABLE person; +REMOVE TABLE comic_book; +REMOVE TABLE publisher; +REMOVE TABLE book; + +DEFINE FIELD comics ON person TYPE option>> REFERENCE; +DEFINE FIELD products ON publisher TYPE option>> REFERENCE; +DEFINE FIELD owners ON comic_book TYPE references; +DEFINE FIELD publisher ON comic_book TYPE references; + +CREATE person:one, person:two SET comics = [comic_book:one]; +CREATE publisher:one SET products = [comic_book:one, book:one]; +CREATE comic_book:one SET title = "Loki, God of Stories"; +SELECT * FROM comic_book; +``` + +```surql title="Output" +[ + { + id: comic_book:one, + owners: [ + person:one, + person:two + ], + publisher: [ + publisher:one + ], + title: 'Loki, God of Stories' + } +] +``` + +## Specifying linking tables and/or field names + diff --git a/src/content/doc-surrealql/datamodel/sets.mdx b/src/content/doc-surrealql/datamodel/sets.mdx index 03e133f9b..1bbeded86 100644 --- a/src/content/doc-surrealql/datamodel/sets.mdx +++ b/src/content/doc-surrealql/datamodel/sets.mdx @@ -1,5 +1,5 @@ --- -sidebar_position: 17 +sidebar_position: 18 sidebar_label: Sets title: Sets | SurrealQL description: A set is a collection type of deduplicated values that can have a maximum size limit. diff --git a/src/content/doc-surrealql/datamodel/strings.mdx b/src/content/doc-surrealql/datamodel/strings.mdx index 4cef162cf..510aee13e 100644 --- a/src/content/doc-surrealql/datamodel/strings.mdx +++ b/src/content/doc-surrealql/datamodel/strings.mdx @@ -1,5 +1,5 @@ --- -sidebar_position: 18 +sidebar_position: 19 sidebar_label: Strings title: Strings | SurrealQL description: Strings can be used to store text values. All string values can include Unicode values, emojis, tab characters, and line breaks. diff --git a/src/content/doc-surrealql/datamodel/uuid.mdx b/src/content/doc-surrealql/datamodel/uuid.mdx index 92220a07b..f64acd74e 100644 --- a/src/content/doc-surrealql/datamodel/uuid.mdx +++ b/src/content/doc-surrealql/datamodel/uuid.mdx @@ -1,5 +1,5 @@ --- -sidebar_position: 19 +sidebar_position: 20 sidebar_label: UUIDs title: UUIDs | SurrealQL description: UUID values in SurrealQL represent UUID values diff --git a/src/content/doc-surrealql/datamodel/values.mdx b/src/content/doc-surrealql/datamodel/values.mdx index 070c43106..4c8343881 100644 --- a/src/content/doc-surrealql/datamodel/values.mdx +++ b/src/content/doc-surrealql/datamodel/values.mdx @@ -1,5 +1,5 @@ --- -sidebar_position: 20 +sidebar_position: 21 sidebar_label: Values title: Values | SurrealQL description: Every type in SurrealDB is a value diff --git a/src/content/doc-surrealql/statements/define/field.mdx b/src/content/doc-surrealql/statements/define/field.mdx index 06f6d0258..72f643ac0 100644 --- a/src/content/doc-surrealql/statements/define/field.mdx +++ b/src/content/doc-surrealql/statements/define/field.mdx @@ -21,6 +21,14 @@ The `DEFINE FIELD` statement allows you to instantiate a named field on a table, ```syntax title="SurrealQL Syntax" DEFINE FIELD [ OVERWRITE | IF NOT EXISTS ] @name ON [ TABLE ] @table [ [ FLEXIBLE ] TYPE @type ] + [ REFERENCE + [ ON DELETE REJECT | + ON DELETE CASCADE | + ON DELETE IGNORE | + ON DELETE REJECT | + ON DELETE UNSET | + ON DELETE THEN @expression ] + ] [ DEFAULT @expression ] [ READONLY ] [ VALUE @expression ] @@ -507,3 +515,12 @@ DEFINE FIELD filter ON TABLE search_settings TYPE | { type: "Snowball", language: string } | { type: "Uppercase" }; ``` + + +## Defining a reference + + + +A field that is a record link (type `record`, `option`, `array>`, and so on) can be defined as a `REFERENCE`. If this clause is used, any linked to record will be able to define a field of its own of type `references` which will be aware of the incoming links. + +For more information, see [the page in the datamodel section on references](/docs/surrealql/datamodel/references). \ No newline at end of file From 8ded302f59340c6d98f50416f3de81d91bd0b46c Mon Sep 17 00:00:00 2001 From: Dave MacLeod <56599343+Dhghomon@users.noreply.github.com> Date: Tue, 24 Dec 2024 16:23:00 +0900 Subject: [PATCH 02/15] Add more content --- .../doc-surrealql/datamodel/references.mdx | 78 ++++++++++++++++++- 1 file changed, 77 insertions(+), 1 deletion(-) diff --git a/src/content/doc-surrealql/datamodel/references.mdx b/src/content/doc-surrealql/datamodel/references.mdx index 11b98345d..c58a66e91 100644 --- a/src/content/doc-surrealql/datamodel/references.mdx +++ b/src/content/doc-surrealql/datamodel/references.mdx @@ -113,5 +113,81 @@ SELECT * FROM comic_book; ] ``` -## Specifying linking tables and/or field names +## Specifying linking tables and field names +A field of type `references` can be further narrowed down to specify not just the table name, but also the field name of the referring record. + +In the comic book example, this can be used to keep track of which people own comic books (via a `comics` field on the `person` table), versus those who borrow those (via a separate `borrowed_comics`) field. Any `comic_book` can keep track of these separately by defining one field with the type `references`, and another field with the type `references`. + +```surql +DEFINE FIELD comics ON person TYPE option>> REFERENCE; +DEFINE FIELD borrowed_comics ON person TYPE option>> REFERENCE; +DEFINE FIELD owned_by ON comic_book TYPE references; +DEFINE FIELD borrowed_by ON comic_book TYPE references; + +CREATE person:one SET comics = [comic_book:one]; +CREATE person:two SET borrowed_comics = [comic_book:one]; +CREATE comic_book:one SET title = "Loki, God of Stories"; +SELECT * FROM comic_book; +``` + +```surql title="Output" +[ + { + borrowed_by: [ + person:two + ], + id: comic_book:one, + owned_by: [ + person:one + ], + title: 'Loki, God of Stories' + } +] +``` + +## Specifying deletion behaviour + +When keeping track of references, it is very likely that you will want some behaviour to happen when a reference is deleted. Take the following example of a `person` who owns a `comic_book`, which is later deleted. However, a follow-up `SELECT * FROM person` still shows the comic book. + +```surql +DEFINE FIELD comics ON person TYPE option>> REFERENCE; +DEFINE FIELD owned_by ON comic_book TYPE references; + +CREATE comic_book:one SET title = "Loki, God of Stories"; +CREATE person:one SET comics = [comic_book:one]; +DELETE comic_book:one; +SELECT * FROM person; +``` + +```surql title="Output" +[ + { + comics: [ + comic_book:one + ], + id: person:one + } +] +``` + +A query using `INFO FOR TABLE person` shows that the actual statement created using `REFERENCE` does not finish at this point, but includes the clause `ON DELETE IGNORE`. + +```surql +{ + events: {}, + fields: { + comics: 'DEFINE FIELD comics ON person TYPE option>> REFERENCE ON DELETE IGNORE PERMISSIONS FULL', + "comics[*]": 'DEFINE FIELD comics[*] ON person TYPE record REFERENCE ON DELETE IGNORE PERMISSIONS FULL' + }, + indexes: {}, + lives: {}, + tables: {} +} +``` + +This `ON DELETE` clause can be modified to have some other behaviour besides ignoring when a reference is deleted. + +### ON DELETE REJECT + +`ON DELETE REJECT` will outright make it impossible to delete a record that is referenced from somewhere else. \ No newline at end of file From 5cde628e62ae6439fd43e6a0b9b23ba78b8a35c4 Mon Sep 17 00:00:00 2001 From: Dave MacLeod <56599343+Dhghomon@users.noreply.github.com> Date: Mon, 30 Dec 2024 10:49:43 +0900 Subject: [PATCH 03/15] record::refs() examples --- .../functions/database/record.mdx | 103 +++++++++++++++++- 1 file changed, 102 insertions(+), 1 deletion(-) diff --git a/src/content/doc-surrealql/functions/database/record.mdx b/src/content/doc-surrealql/functions/database/record.mdx index 469156c87..12810530b 100644 --- a/src/content/doc-surrealql/functions/database/record.mdx +++ b/src/content/doc-surrealql/functions/database/record.mdx @@ -34,6 +34,10 @@ These functions can be used to retrieve specific metadata from a SurrealDB Recor record::tb() Extracts and returns the table name from a SurrealDB Record ID + + record::refs() + Extracts and returns the table name from a SurrealDB Record ID + @@ -83,7 +87,104 @@ RETURN record::id(person:tobie); "tobie" ``` -
+## `record::refs` + + + +The `record::refs` function returns the record IDs of any records that have a [record link](/docs/surrealql/datamodel/records) along with a `REFERENCES` clause. + +```surql title="API DEFINITION" +record::refs(record) -> array +record::refs(record, $table_name: string) -> array +record::refs(record, $table_name: string, $field_name: string) -> array +``` + +This function can be used on its own to return all references to a single record. + +```surql +DEFINE FIELD best_friend ON person TYPE option> REFERENCE; + +-- Both Billy and Bobby think Gaston is their best friend +CREATE person:billy, person:bobby SET best_friend = person:gaston; +-- But not Gaston +CREATE person:gaston SET best_friend = NONE; + +person:gaston.refs(); +``` + +```surql title="Output" +[ + person:billy, + person:bobby +] +``` + +It can be followed by a single string to filter references to only include those from a certain table. + +```surql +DEFINE FIELD located_in ON city TYPE option> REFERENCE; +DEFINE FIELD located_in ON state TYPE option> REFERENCE; + +CREATE country:germany; +CREATE state:bavaria, city:munich SET located_in = country:germany; + +country:germany.refs('city'); +country:germany.refs('state'); +``` + +```surql title="Output" +-------- Query -------- + +[ + city:munich +] + +-------- Query -------- + +[ + state:bavaria +] +``` + +If followed by a second string, it will filter references by table name as well as field name. + +```surql +DEFINE FIELD owner ON dog TYPE option> REFERENCE; +DEFINE FIELD acquaintances ON dog TYPE option>> REFERENCE; +DEFINE FIELD roommates ON cat TYPE option> REFERENCE; +DEFINE FIELD acquaintances ON cat TYPE option>> REFERENCE; + +CREATE person:one, person:two, person:three; +CREATE dog:mr_bark SET owner = person:one, acquaintances = [person:two, person:three]; +CREATE cat:mr_meow SET roommates = [person:one], acquaintances = [person:two, person:three]; + +-- All the dogs that consider person:one the owner +person:one.refs('dog', 'owner'); +-- All the cats that consider person:one the roommate +person:one.refs('cat', 'roommate'); +-- All the dogs acquainted with person:two +person:two.refs('dog', 'acquaintances'); +``` + +```surql title="Output" +-------- Query -------- + +[ + dog:mr_bark +] + +-------- Query -------- + +[ + cat:mr_meow +] + +-------- Query -------- + +[ + dog:mr_bark +] +``` ## `record::tb` From 3f09115500887eac84e14d0d4c86feb677c03f2a Mon Sep 17 00:00:00 2001 From: Dave MacLeod <56599343+Dhghomon@users.noreply.github.com> Date: Mon, 30 Dec 2024 12:38:16 +0900 Subject: [PATCH 04/15] Add .refs(), more ON DELETE examples --- .../doc-surrealql/datamodel/references.mdx | 212 +++++++++++++++++- 1 file changed, 206 insertions(+), 6 deletions(-) diff --git a/src/content/doc-surrealql/datamodel/references.mdx b/src/content/doc-surrealql/datamodel/references.mdx index c58a66e91..03a0d46f3 100644 --- a/src/content/doc-surrealql/datamodel/references.mdx +++ b/src/content/doc-surrealql/datamodel/references.mdx @@ -81,11 +81,6 @@ Because the `owners` field on `comic_book` looks for any and all references, it This can be fixed by changing the single field of type `references` to two fields, one of which is a `references`, and the other a `references`. ```surql -REMOVE TABLE person; -REMOVE TABLE comic_book; -REMOVE TABLE publisher; -REMOVE TABLE book; - DEFINE FIELD comics ON person TYPE option>> REFERENCE; DEFINE FIELD products ON publisher TYPE option>> REFERENCE; DEFINE FIELD owners ON comic_book TYPE references; @@ -146,6 +141,48 @@ SELECT * FROM comic_book; ] ``` +## Using the `.refs()` method + +The `.refs()` method can be called on a record to find references to it in the same way that a field can be defined as a `references`. Similar to defining a field of type `references`, this function can also narrow down the references to a record by only returning references from a certain table, or a certain table and field name. + +```surql +DEFINE FIELD comics ON person TYPE option>> REFERENCE; +DEFINE FIELD borrowed_comics ON person TYPE option>> REFERENCE; + +CREATE person:one SET comics = [comic_book:one]; +CREATE person:two SET borrowed_comics = [comic_book:one]; +CREATE comic_book:one SET title = "Loki, God of Stories"; + +-- All references +comic_book:one.refs(); +-- All references from 'person' records +comic_book:one.refs('person'); +-- All references from 'person' records via a field 'comics' +comic_book:one.refs('person', 'comics'); +``` + +```surql title="Output" +-------- Query -------- + +[ + person:two, + person:one +] + +-------- Query -------- + +[ + person:two, + person:one +] + +-------- Query -------- + +[ + person:one +] +``` + ## Specifying deletion behaviour When keeping track of references, it is very likely that you will want some behaviour to happen when a reference is deleted. Take the following example of a `person` who owns a `comic_book`, which is later deleted. However, a follow-up `SELECT * FROM person` still shows the comic book. @@ -188,6 +225,169 @@ A query using `INFO FOR TABLE person` shows that the actual statement created us This `ON DELETE` clause can be modified to have some other behaviour besides ignoring when a reference is deleted. +### ON DELETE IGNORE + +As shown in the previous section, this is the default behaviour for references. + +```surql +-- Default, behaviour, so identical to: +-- DEFINE FIELD friends ON person TYPE option>> REFERENCE; +DEFINE FIELD friends ON person TYPE option>> REFERENCE ON DELETE IGNORE; +DEFINE FIELD friended_by ON person TYPE references; + +CREATE person:one SET friends = [person:two]; +CREATE person:two; +DELETE person:one; +person:two.*; +``` + +As the deletion of `person:one` is ignored when calculating the `friended_by` field, it will still show `person:one` even though the record itself has been deleted. + +```surql +{ + friended_by: [ + person:one + ], + id: person:two +} +``` + +### ON DELETE UNSET + +`ON DELETE UNSET` will unset (remove) any linked records that are deleted. This can be thought of as the opposite of `ON DELETE IGNORE`. + +```surql +DEFINE FIELD comments ON person TYPE option>> REFERENCE ON DELETE UNSET; +DEFINE FIELD author ON comment TYPE references; + +CREATE person:one; +UPDATE person:one SET comments += (CREATE ONLY comment SET text = "Estonia is bigger than I expected!").id; +-- Give this one a parameter name so it can be deleted later +LET $comment = CREATE ONLY comment SET text = "I don't get the joke here?"; +UPDATE person:one SET comments += $comment.id; +-- Now delete it +DELETE $comment; +-- Only one comment shows up for person:one now +person:one.comments.*.*; +``` + +```surql title="Output of person:one queries" +-------- Query -------- + +[ + { + author: [ + person:one + ], + id: comment:idxhzumaggzb7g3ym6bl, + text: 'Estonia is bigger than I expected!' + }, + { + author: [ + person:one + ], + id: comment:58uasmx4s0vdjjehfyjz, + text: "I don't get the joke here?" + } +] + +-------- Query -------- + +[ + { + author: [ + person:one + ], + id: comment:uma97u2j2q4tlamzc9yv, + text: 'Estonia is bigger than I expected!' + } +] +``` + +### ON DELETE CASCADE + +The `ON DELETE CASCADE` will cause a record to be deleted if any record it references is deleted. This is useful for records that should not exist if a record that links to them no longer exists. + +```surql +REMOVE DATABASE db; + +DEFINE FIELD author ON comment TYPE record REFERENCE ON DELETE CASCADE; +DEFINE FIELD comments ON person TYPE references; + +CREATE person:one; +CREATE comment SET author = person:one, text = "5/10 for this blog post. The problems I have with it are..."; +CREATE comment SET author = person:one, text = "WOW! I never knew you could cut a rope with an arrow."; + +-- Show all the details of comments for 'person:one' +person:one.comments.*.*; +DELETE person:one; +-- Comments no longer exist +SELECT * FROM comment; +``` + +```surql title="Output" +-------- Query -------- + +[ + { + author: person:one, + id: comment:8msvp0egg8cdlyu4vvn9, + text: 'WOW! I never knew you could cut a rope with an arrow.' + }, + { + author: person:one, + id: comment:i72qfjy59vbn81hk6lrm, + text: '5/10 for this blog post. The problems I have with it are...' + } +] + +-------- Query -------- + +[] + +-------- Query -------- + +[] +``` + ### ON DELETE REJECT -`ON DELETE REJECT` will outright make it impossible to delete a record that is referenced from somewhere else. \ No newline at end of file +`ON DELETE REJECT` will outright make it impossible to delete a record that is referenced from somewhere else. For example, consider the case in which a house should not be demolished (deleted) until it has been disconnected from utilities such as gas, water, electricity, and so on. This can be simulated in a schema by adding a `REFERENCE ON DELETE REJECT` to the `utility` table, making it impossible for any `house` to be deleted if they link to it. + +```surql +DEFINE FIELD connected_to ON utility TYPE option>> REFERENCE ON DELETE REJECT; +DEFINE FIELD using ON house TYPE references; + +CREATE house:one; +CREATE utility:gas, utility:water SET connected_to = [house:one]; +``` + +At this point, the `using` field on `house:one` automatically picks up the two references, + +```surql +house:one.*; +DELETE house:one; +``` + +```surql title="Output" +-------- Query -------- + +{ + id: house:one, + using: [ + utility:gas, + utility:water + ] +} + +-------- Query -------- + +'Cannot delete `house:one` as it is referenced by `utility:gas` with an ON DELETE REJECT clause' +``` + +UPDATE utility:gas SET connected_to -= house:one; +UPDATE utility:water SET connected_to -= house:one; + +DELETE house:one; +``` + From d24e178cba531bb3fb102d32118b1f1e2efaaca3 Mon Sep 17 00:00:00 2001 From: Dave MacLeod <56599343+Dhghomon@users.noreply.github.com> Date: Mon, 30 Dec 2024 14:04:51 +0900 Subject: [PATCH 05/15] Record links now have some advantages that only graphs had previously --- src/content/doc-surrealql/statements/relate.mdx | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/content/doc-surrealql/statements/relate.mdx b/src/content/doc-surrealql/statements/relate.mdx index 43263ac4b..0184ed9c5 100644 --- a/src/content/doc-surrealql/statements/relate.mdx +++ b/src/content/doc-surrealql/statements/relate.mdx @@ -19,10 +19,11 @@ Otherwise, edge tables behave like normal tables in terms of [updating](/docs/su Another option for connecting data is using [record links](/docs/surrealql/datamodel/records). Record links consist of a field with record IDs that serve as uni-directional links. The key differences are that graph relations have the following benefits over record links: -- They are kept in a separate table as opposed to a field inside a record. -- Offer bi-directional querying. -- Offer referential integrity. -- Allow you to store data alongside the relationship. +- Graph relations are kept in a separate table as opposed to a field inside a record. +- Graph relations you to store data alongside the relationship. +- Graph relations have their own syntax that makes it easy to build and visualize edge queries. + +Graph relations also offer built-in bi-directional querying and referential integrity. As of SurrealDB 2.2.0, record links also offer these two advantages if they are defined inside a [`DEFINE FIELD`](/docs/surrealql/statements/define/field) statement using the `REFERENCES` clause. For more information, see [the page on record references](/docs/surrealql/datamodel/references). ### Statement syntax From 53f47276c78764fc6765032902eb396eeea1a2be Mon Sep 17 00:00:00 2001 From: Dave MacLeod <56599343+Dhghomon@users.noreply.github.com> Date: Tue, 31 Dec 2024 11:04:16 +0900 Subject: [PATCH 06/15] Add ON DELETE THEN --- .../doc-surrealql/datamodel/references.mdx | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/src/content/doc-surrealql/datamodel/references.mdx b/src/content/doc-surrealql/datamodel/references.mdx index 03a0d46f3..408ccff79 100644 --- a/src/content/doc-surrealql/datamodel/references.mdx +++ b/src/content/doc-surrealql/datamodel/references.mdx @@ -385,9 +385,58 @@ DELETE house:one; 'Cannot delete `house:one` as it is referenced by `utility:gas` with an ON DELETE REJECT clause' ``` +```surql UPDATE utility:gas SET connected_to -= house:one; UPDATE utility:water SET connected_to -= house:one; DELETE house:one; ``` +### ON DELETE THEN + +The `ON DELETE THEN` clause allows custom logic to take place when a reference is deleted. This clause includes a parameters called `$this` to refer to the record in question, and `$reference` for the reference. + +In the following example, a `person` record's `comments` field will remove any comments when they are deleted, but also add the same comment to a different field called `deleted_comments`. + +```surql +DEFINE FIELD comments ON person TYPE option>> REFERENCE ON DELETE THEN { + UPDATE $this SET + deleted_comments += $reference, + comments -= $reference; +}; +DEFINE FIELD author ON comment TYPE references; + +CREATE person:one SET comments += (CREATE ONLY comment SET text = "Estonia is bigger than I expected!").id; +LET $comment = CREATE ONLY comment SET text = "I don't get the joke here?"; +UPDATE person:one SET comments += $comment.id; +DELETE $comment; +SELECT * FROM person:one; +``` + +```surql title="person:one before and after comment is deleted" +-------- Query -------- + +[ + { + comments: [ + comment:lbeyh2icushpwo0ak5ux, + comment:90tdnyoa14cge2ocmep7 + ], + id: person:one + } +] + +-------- Query -------- + +[ + { + comments: [ + comment:lbeyh2icushpwo0ak5ux + ], + deleted_comments: [ + comment:90tdnyoa14cge2ocmep7 + ], + id: person:one + } +] +``` \ No newline at end of file From cacee66ad6d529150882527fe89c9f4070fb67d9 Mon Sep 17 00:00:00 2001 From: Dave MacLeod <56599343+Dhghomon@users.noreply.github.com> Date: Tue, 31 Dec 2024 13:55:55 +0900 Subject: [PATCH 07/15] Start rewrite of graph relations page --- .../reference-guide/graph_relations.mdx | 53 +++++++++++++++++-- 1 file changed, 48 insertions(+), 5 deletions(-) diff --git a/src/content/doc-surrealdb/reference-guide/graph_relations.mdx b/src/content/doc-surrealdb/reference-guide/graph_relations.mdx index 7addb6dd0..781e7bfea 100644 --- a/src/content/doc-surrealdb/reference-guide/graph_relations.mdx +++ b/src/content/doc-surrealdb/reference-guide/graph_relations.mdx @@ -15,7 +15,7 @@ The first item to take into account when using graph relations is whether they a SurrealDB has two main ways to create relations between one record and another: record links, and graph relations. -A record link is a simple pointer from one record to another, a link that exists any time a record holds the record ID of another record. Record links are the most efficient method because record IDs are direct pointers to the data of a record, and do not require a table scan. +A record link is a simple pointer from one record to another, a link that exists any time a record holds the record ID of another record. Record links are extremely efficient because record IDs are direct pointers to the data of a record, and do not require a table scan. Take the following example that creates one `user` who has written two `comment`s. @@ -32,7 +32,7 @@ UPDATE $new_user SET comments += (CREATE ONLY comment SET .id; ``` -Querying a record link is easy as the link is unidirectional with nothing in between. In this case, the linked comments are simply a field on a `user` record and accessing them is as simple as any other field on a `user` record. +Querying a record link is easy as the link by default is unidirectional with nothing in between. In this case, the linked comments are simply a field on a `user` record and accessing them is as simple as any other field on a `user` record. ```surql SELECT @@ -59,7 +59,7 @@ FROM user; ] ``` -The unidirectionality of a record link is also a limitation, because the only way to query in the other direction is by using a subquery. With some knowledge of SurrealQL this is certainly doable, but a case like this is an indication that a graph link may be the better solution. +Until SurrealDB version 2.2.0, record links were strictly unidirectional. The only way to query in the other direction was by using a subquery, which made graph edges the only option for bidirectional links. ```surql SELECT @@ -97,7 +97,49 @@ FROM comment; ] ``` -The other limitation is that there is no metadata about the context in which the comment was created. Take the following metadata for instance which contains information about a user's current location, operating system, and mood. Where does this data belong? +Since version 2.2.0, a record link can be bidirectional by [defining a field](/docs/surrealql/statements/define/field) with the `REFERENCE` clause, allowing referenced records to define a field or use the `.refs()` method to track incoming references. + +```surql +DEFINE FIELD comments ON user TYPE option>> REFERENCE; +DEFINE FIELD author ON comment TYPE references; + +LET $new_user = CREATE ONLY user SET name = "User McUserson"; +-- Create a new comment, use the output to update the user +UPDATE $new_user SET comments += (CREATE ONLY comment:one SET + text = "I learned something new!", + created_at = time::now()) + .id; +UPDATE $new_user SET comments += (CREATE ONLY comment:two SET + text = "I don't get it, can you explain?", + created_at = time::now()) + .id; + +-- 'author' field is populated with the 'user' who wrote the comment +SELECT * FROM ONLY comment:one; +-- Or use .refs() to grab the references +comment:one.refs(); +``` + +```surql title="Output" +-------- Query -------- + +{ + author: [ + user:ie8yc8woe0rwo5cgln57 + ], + created_at: d'2024-12-31T04:51:47.504Z', + id: comment:one, + text: 'I learned something new!' +} + +-------- Query -------- + +[ + user:ie8yc8woe0rwo5cgln57 +] +``` + +The main limitation is that there is no metadata about the context in which the comment was created. Take the following metadata for instance which contains information about a user's current location, operating system, and mood. Where does this data belong? ```surql { @@ -247,7 +289,8 @@ RELATE person:two->friends_with->person:one; -------- Query -------- -"Database index `only_one_friendship` already contains '[person:one, person:two]', with record `friends_with:dblidwpc44qqz5bvioiu`" +"Database index `only_one_friendship` already contains '[person:one, person:two]', +with record `friends_with:dblidwpc44qqz5bvioiu`" ``` ### Querying a graph relation between equals From b754af7816f91f556691cc6b40843c638c05078e Mon Sep 17 00:00:00 2001 From: Dave MacLeod <56599343+Dhghomon@users.noreply.github.com> Date: Thu, 2 Jan 2025 10:45:33 +0900 Subject: [PATCH 08/15] Some more content --- .../reference-guide/graph_relations.mdx | 42 +++++++++++++++++-- 1 file changed, 38 insertions(+), 4 deletions(-) diff --git a/src/content/doc-surrealdb/reference-guide/graph_relations.mdx b/src/content/doc-surrealdb/reference-guide/graph_relations.mdx index 781e7bfea..389365ccf 100644 --- a/src/content/doc-surrealdb/reference-guide/graph_relations.mdx +++ b/src/content/doc-surrealdb/reference-guide/graph_relations.mdx @@ -59,7 +59,7 @@ FROM user; ] ``` -Until SurrealDB version 2.2.0, record links were strictly unidirectional. The only way to query in the other direction was by using a subquery, which made graph edges the only option for bidirectional links. +Until SurrealDB version 2.2.0, record links were strictly unidirectional. The only way to query in the other direction was by using a subquery, which made graph edges the only easy option for bidirectional links. ```surql SELECT @@ -68,6 +68,13 @@ SELECT -- for the id of the current comment (SELECT id, name FROM user WHERE $parent.id IN comments) AS author FROM comment; + +-- Equivalent graph query is much easier +-- to read and write +SELECT + *, + <-wrote<-author +FROM comment; ``` ```surql @@ -139,7 +146,19 @@ comment:one.refs(); ] ``` -The main limitation is that there is no metadata about the context in which the comment was created. Take the following metadata for instance which contains information about a user's current location, operating system, and mood. Where does this data belong? +If your use case involves bidirectional links, consider the following items to make a decision. + +Record links are preferred if: + +* Performance is of the utmost importance. + +Graph links are preferred if: + +* You want to create links without touching the database schema. +* You want to put together complex queries that take advantage of SurrealQL's expressive arrow syntax, like `->wrote->comment<-wrote<-person->wrote->comment FROM person`. +* You want to + +Finally, graph links arle not just preferred but almost certainly necessary if you need to keep metadata about the context in which a link is created. Take the following metadata for the examples above involving a user and its comments which contains information about a user's current location, operating system, and mood. Where does this data belong? ```surql { @@ -149,7 +168,18 @@ The main limitation is that there is no metadata about the context in which the } ``` -This metadata isn't information about the user as a whole, nor the comment itself. It's information about the moment in time in which the `user` and `comment` were linked, and thus is best stored in a separate table. If this sort of metadata is necessary, then a graph table is the ideal solution. +This metadata isn't information about the user as a whole, nor the comment itself. It's information about the moment in time in which the `user` and `comment` were linked, and thus is best stored in a separate table. + +Or you might have some information about the link itself, which would also belong nowhere else but inside a graph table. + +```surql +{ + friends_since: d'2024-12-31T06:43:21.981Z', + friendship_strength: 0.4 +} +``` + +If this sort of metadata is necessary, then a graph table is the ideal solution. ## Creating a graph relation @@ -599,4 +629,8 @@ While developed for graph relations in particular, this path can be used in any For more details on SurrealDB's recursive syntax, see the following pages: * [Idioms: recursive paths](/docs/surrealql/datamodel/idioms#recursive-paths) -* [Chapter 8 of Aeon's Surreal Renaissance](/learn/book/chapter-08#longer-relational-queries) \ No newline at end of file +* [Chapter 8 of Aeon's Surreal Renaissance](/learn/book/chapter-08#longer-relational-queries) + +### When links are deleted + +Mention how graph tables are deleted if the records involved are deleted, while record links have the fancy clauses \ No newline at end of file From 9ac2585c5afbe5cbc05e4aaf9c2c0f810ef0a6a7 Mon Sep 17 00:00:00 2001 From: Dave MacLeod <56599343+Dhghomon@users.noreply.github.com> Date: Thu, 2 Jan 2025 12:14:42 +0900 Subject: [PATCH 09/15] Last changes to references.mdx page --- .../doc-surrealql/datamodel/references.mdx | 20 +++++++++---------- .../doc-surrealql/statements/define/field.mdx | 6 +++++- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/content/doc-surrealql/datamodel/references.mdx b/src/content/doc-surrealql/datamodel/references.mdx index 408ccff79..a5893440f 100644 --- a/src/content/doc-surrealql/datamodel/references.mdx +++ b/src/content/doc-surrealql/datamodel/references.mdx @@ -32,7 +32,7 @@ CREATE comic_book:one SET title = "Loki, God of Stories"; SELECT * FROM comic_book; ``` -The linking records will now be picked up automatically from the `comic_book` side. +In the example above, the referencing records will now be picked up automatically from the `comic_book` side. ```surql title="Output" [ @@ -62,7 +62,7 @@ CREATE comic_book:one SET title = "Loki, God of Stories"; SELECT * FROM comic_book; ``` -Because the `owners` field on `comic_book` looks for any and all references, it now includes the publisher as an owner, which is not ideal. +As the `owners` field on `comic_book` only includes a general `references` clause, it will show any and all references to a `comic_book` record. It will thus show the publisher as one of the `owners`, which is not ideal. ```surql title="Output" [ @@ -110,7 +110,7 @@ SELECT * FROM comic_book; ## Specifying linking tables and field names -A field of type `references` can be further narrowed down to specify not just the table name, but also the field name of the referring record. +A field of type `references` can be further narrowed down to specify not just the table name, but also the field name of the referencing record. In the comic book example, this can be used to keep track of which people own comic books (via a `comics` field on the `person` table), versus those who borrow those (via a separate `borrowed_comics`) field. Any `comic_book` can keep track of these separately by defining one field with the type `references`, and another field with the type `references`. @@ -143,7 +143,7 @@ SELECT * FROM comic_book; ## Using the `.refs()` method -The `.refs()` method can be called on a record to find references to it in the same way that a field can be defined as a `references`. Similar to defining a field of type `references`, this function can also narrow down the references to a record by only returning references from a certain table, or a certain table and field name. +To dynamically find references to a record instead of using a `DEFINE FIELD` statement, the `.refs()` method can be used. Similar to defining a field of type `references`, this function can also narrow down the references to a record by only returning references from a certain table, or a certain table and field name. However, a `DEFINE FIELD` which includes a `REFERENCE` clause is still necessary in order to set up the reference tracking in the first place. ```surql DEFINE FIELD comics ON person TYPE option>> REFERENCE; @@ -185,7 +185,7 @@ comic_book:one.refs('person', 'comics'); ## Specifying deletion behaviour -When keeping track of references, it is very likely that you will want some behaviour to happen when a reference is deleted. Take the following example of a `person` who owns a `comic_book`, which is later deleted. However, a follow-up `SELECT * FROM person` still shows the comic book. +When working with record links, it is very likely that you will want some behaviour to happen when a referencing link is deleted. Take the following example of a `person` who owns a `comic_book`, which is later deleted. Despite the deletion, a follow-up `SELECT * FROM person` still shows the comic book. ```surql DEFINE FIELD comics ON person TYPE option>> REFERENCE; @@ -208,7 +208,7 @@ SELECT * FROM person; ] ``` -A query using `INFO FOR TABLE person` shows that the actual statement created using `REFERENCE` does not finish at this point, but includes the clause `ON DELETE IGNORE`. +A query using `INFO FOR TABLE person` shows that the actual statement created using `REFERENCE` does not finish at this point, but includes the clause `ON DELETE IGNORE`. This is the default behaviour for references. ```surql { @@ -223,11 +223,11 @@ A query using `INFO FOR TABLE person` shows that the actual statement created us } ``` -This `ON DELETE` clause can be modified to have some other behaviour besides ignoring when a reference is deleted. +This `ON DELETE` clause can be modified to have some other behaviour when a reference is deleted. ### ON DELETE IGNORE -As shown in the previous section, this is the default behaviour for references. +As shown in the previous section, `ON DELETE IGNORE` is the default behaviour for references and this clause will be added automatically if not specified. It can be added manually to a statement to hint to others reading the code that this behaviour is desired. ```surql -- Default, behaviour, so identical to: @@ -309,8 +309,6 @@ person:one.comments.*.*; The `ON DELETE CASCADE` will cause a record to be deleted if any record it references is deleted. This is useful for records that should not exist if a record that links to them no longer exists. ```surql -REMOVE DATABASE db; - DEFINE FIELD author ON comment TYPE record REFERENCE ON DELETE CASCADE; DEFINE FIELD comments ON person TYPE references; @@ -394,7 +392,7 @@ DELETE house:one; ### ON DELETE THEN -The `ON DELETE THEN` clause allows custom logic to take place when a reference is deleted. This clause includes a parameters called `$this` to refer to the record in question, and `$reference` for the reference. +The `ON DELETE THEN` clause allows for custom logic when a reference is deleted. This clause includes a parameters called `$this` to refer to the record in question, and `$reference` for the reference. In the following example, a `person` record's `comments` field will remove any comments when they are deleted, but also add the same comment to a different field called `deleted_comments`. diff --git a/src/content/doc-surrealql/statements/define/field.mdx b/src/content/doc-surrealql/statements/define/field.mdx index 72f643ac0..e576362cb 100644 --- a/src/content/doc-surrealql/statements/define/field.mdx +++ b/src/content/doc-surrealql/statements/define/field.mdx @@ -78,7 +78,7 @@ DEFINE FIELD user_id ON TABLE user TYPE uuid|int; ### Array type -You can also set a field to have the array data type. The array data type can be used to store a list of values. You can also set the data type of the array's contents. +You can also set a field to have the array data type. The array data type can be used to store a list of values. You can also set the data type of the array's contents, as well as the maximum number of items that it can hold. ```surql -- Set a field to have the array data type @@ -89,6 +89,10 @@ DEFINE FIELD posts ON TABLE user TYPE array; -- Set a field to have the array object data type DEFINE FIELD emails ON TABLE user TYPE array; + +-- Field for a block in a game showing the possible directions a character can move next. +-- The array can contain no more than four directions +DEFINE FIELD next_paths ON TABLE block TYPE array<"north" | "east" | "south" | "west", 4>; ``` ### Making a field optional From 5b66638ca34c6711fcf26671daaf9302580d81d3 Mon Sep 17 00:00:00 2001 From: Dave MacLeod <56599343+Dhghomon@users.noreply.github.com> Date: Thu, 2 Jan 2025 13:06:39 +0900 Subject: [PATCH 10/15] Add two weighting examples --- .../reference-guide/graph_relations.mdx | 194 +++++++++++++++++- 1 file changed, 192 insertions(+), 2 deletions(-) diff --git a/src/content/doc-surrealdb/reference-guide/graph_relations.mdx b/src/content/doc-surrealdb/reference-guide/graph_relations.mdx index 389365ccf..b19c9ace8 100644 --- a/src/content/doc-surrealdb/reference-guide/graph_relations.mdx +++ b/src/content/doc-surrealdb/reference-guide/graph_relations.mdx @@ -158,7 +158,7 @@ Graph links are preferred if: * You want to put together complex queries that take advantage of SurrealQL's expressive arrow syntax, like `->wrote->comment<-wrote<-person->wrote->comment FROM person`. * You want to -Finally, graph links arle not just preferred but almost certainly necessary if you need to keep metadata about the context in which a link is created. Take the following metadata for the examples above involving a user and its comments which contains information about a user's current location, operating system, and mood. Where does this data belong? +Finally, graph links are not just preferred but almost certainly necessary if you need to keep metadata about the context in which a link is created. Take the following metadata for the examples above involving a user and its comments which contains information about a user's current location, operating system, and mood. Where does this data belong? ```surql { @@ -179,7 +179,197 @@ Or you might have some information about the link itself, which would also belon } ``` -If this sort of metadata is necessary, then a graph table is the ideal solution. +Graph links also excel when it comes to weighting relations. This can be done through a field on the graph table... + +```surql +-- Create 4 'npc' records +CREATE |npc:1..4|; + +FOR $npc IN SELECT * FROM npc { + -- Give each npc 20 random interactions + FOR $_ IN 0..20 { + -- Looks for a random NPC, use array::complement to filter out self + LET $counterpart = rand::enum(array::complement((SELECT * FROM npc), [$npc])); + -- See if they have a relation yet + LET $existing = SELECT * FROM knows WHERE in = $npc.id AND out = $counterpart.id; + -- If relation exists, increase 'greeted' by one + IF !!$existing { + UPDATE $existing SET greeted += 1; + -- Otherwise create the relation and set 'greeted' to 1 + } ELSE { + RELATE $npc->knows->$counterpart SET greeted = 1; + } + }; +}; + +SELECT + id, + ->knows.{ like_strength: greeted, with: out } AS relations + FROM npc; +``` + +```surql title="Which NPC each NPC likes the most" +[ + { + id: npc:1, + relations: [ + { + like_strength: 8, + with: npc:3 + }, + { + like_strength: 8, + with: npc:4 + }, + { + like_strength: 4, + with: npc:2 + } + ] + }, + { + id: npc:2, + relations: [ + { + like_strength: 10, + with: npc:1 + }, + { + like_strength: 4, + with: npc:3 + }, + { + like_strength: 6, + with: npc:4 + } + ] + }, + { + id: npc:3, + relations: [ + { + like_strength: 6, + with: npc:2 + }, + { + like_strength: 3, + with: npc:4 + }, + { + like_strength: 11, + with: npc:1 + } + ] + }, + { + id: npc:4, + relations: [ + { + like_strength: 7, + with: npc:1 + }, + { + like_strength: 6, + with: npc:3 + }, + { + like_strength: 7, + with: npc:2 + } + ] + } +] +``` + +...or through counting the number of edges. + +```surql +-- Create 4 'npc' records +CREATE |npc:1..4|; + +FOR $npc IN SELECT * FROM npc { + -- Give each npc 20 random interactions + FOR $_ IN 0..20 { + -- Looks for a random NPC, use array::complement to filter out self + LET $counterpart = rand::enum(array::complement((SELECT * FROM npc), [$npc])); + RELATE $npc->greeted->$counterpart; + }; +}; + +SELECT + count() AS like_strength, + in AS npc, + out AS counterpart +FROM greeted +GROUP BY npc, counterpart; +``` + +```surql title="Which NPC each NPC likes the most" +[ + { + counterpart: npc:2, + like_strength: 6, + npc: npc:1 + }, + { + counterpart: npc:3, + like_strength: 9, + npc: npc:1 + }, + { + counterpart: npc:4, + like_strength: 5, + npc: npc:1 + }, + { + counterpart: npc:1, + like_strength: 9, + npc: npc:2 + }, + { + counterpart: npc:3, + like_strength: 6, + npc: npc:2 + }, + { + counterpart: npc:4, + like_strength: 5, + npc: npc:2 + }, + { + counterpart: npc:1, + like_strength: 10, + npc: npc:3 + }, + { + counterpart: npc:2, + like_strength: 7, + npc: npc:3 + }, + { + counterpart: npc:4, + like_strength: 3, + npc: npc:3 + }, + { + counterpart: npc:1, + like_strength: 6, + npc: npc:4 + }, + { + counterpart: npc:2, + like_strength: 4, + npc: npc:4 + }, + { + counterpart: npc:3, + like_strength: 10, + npc: npc:4 + } +] +``` + +If this sort of metadata or weighting is necessary, then a graph table is the ideal solution. ## Creating a graph relation From c6dc50ed6b75820ebfac59dac5f2387e259f9e61 Mon Sep 17 00:00:00 2001 From: Dave MacLeod <56599343+Dhghomon@users.noreply.github.com> Date: Thu, 2 Jan 2025 13:45:56 +0900 Subject: [PATCH 11/15] Add bit on deletion behaviour --- .../reference-guide/graph_relations.mdx | 24 +++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/src/content/doc-surrealdb/reference-guide/graph_relations.mdx b/src/content/doc-surrealdb/reference-guide/graph_relations.mdx index b19c9ace8..1a8fa2c98 100644 --- a/src/content/doc-surrealdb/reference-guide/graph_relations.mdx +++ b/src/content/doc-surrealdb/reference-guide/graph_relations.mdx @@ -151,12 +151,13 @@ If your use case involves bidirectional links, consider the following items to m Record links are preferred if: * Performance is of the utmost importance. +* You don't need to put complex queries together. +* You want to specify in the schema what behaviour should take place when a linked record is deleted (cascade delete, refuse to delete, ignore, etc.). Graph links are preferred if: * You want to create links without touching the database schema. * You want to put together complex queries that take advantage of SurrealQL's expressive arrow syntax, like `->wrote->comment<-wrote<-person->wrote->comment FROM person`. -* You want to Finally, graph links are not just preferred but almost certainly necessary if you need to keep metadata about the context in which a link is created. Take the following metadata for the examples above involving a user and its comments which contains information about a user's current location, operating system, and mood. Where does this data belong? @@ -823,4 +824,23 @@ For more details on SurrealDB's recursive syntax, see the following pages: ### When links are deleted -Mention how graph tables are deleted if the records involved are deleted, while record links have the fancy clauses \ No newline at end of file +As mentioned above, record links since version 2.2.0 have the ability to specify what behaviour should take place when a referencing link is deleted. Graph links have a simpler behaviour in which they will be deleted if at least of the linked records is deleted. + +```surql +-- likes record created without problems +RELATE person:one->likes->person:two; +CREATE person:one, person:two; +DELETE person:one; +-- 'likes' record is now gone +SELECT * FROM likes; +``` + +A record link allows for more complex behaviour such as the following in which a linked record is removed from the `comments` field if it is deleted, but also adds the record ID to a field called `deleted_comments` for record keeping. For more information on these `ON DELETE` clauses, see the [page on record references](/docs/surrealql/datamodel/references/). + +```surql +DEFINE FIELD comments ON person TYPE option>> REFERENCE ON DELETE THEN { + UPDATE $this SET + deleted_comments += $reference, + comments -= $reference; +}; +``` \ No newline at end of file From 3af6ddb76e31c033738685b2a3b7bb31e3a781dc Mon Sep 17 00:00:00 2001 From: Dave MacLeod <56599343+Dhghomon@users.noreply.github.com> Date: Thu, 2 Jan 2025 14:14:27 +0900 Subject: [PATCH 12/15] (Probably) final changes, remove hyphens --- src/content/doc-surrealdb/integration/rpc.mdx | 2 +- src/content/doc-surrealdb/introduction/mongo.mdx | 2 +- src/content/doc-surrealdb/introduction/sql.mdx | 2 +- src/content/doc-surrealql/datamodel/records.mdx | 2 +- src/content/doc-surrealql/statements/define/indexes.mdx | 4 +++- src/content/doc-surrealql/statements/relate.mdx | 8 ++++---- src/content/doc-surrealql/statements/select.mdx | 2 +- 7 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/content/doc-surrealdb/integration/rpc.mdx b/src/content/doc-surrealdb/integration/rpc.mdx index 02e8625ec..f371c4459 100644 --- a/src/content/doc-surrealdb/integration/rpc.mdx +++ b/src/content/doc-surrealdb/integration/rpc.mdx @@ -2,7 +2,7 @@ sidebar_position: 4 sidebar_label: RPC Protocol title: RPC Protocol | Integration -description: The RPC protocol allows for easy bi-directional communication with SurrealDB. +description: The RPC protocol allows for easy bidirectional communication with SurrealDB. --- import Since from '@components/shared/Since.astro' diff --git a/src/content/doc-surrealdb/introduction/mongo.mdx b/src/content/doc-surrealdb/introduction/mongo.mdx index adf34949d..863b5bba0 100644 --- a/src/content/doc-surrealdb/introduction/mongo.mdx +++ b/src/content/doc-surrealdb/introduction/mongo.mdx @@ -100,7 +100,7 @@ For more in-depth explanations of SurrealDB concepts, see the [concepts page](/d reference and embedding - record links, embedding and graph relations + record links, embedding and graph relations diff --git a/src/content/doc-surrealdb/introduction/sql.mdx b/src/content/doc-surrealdb/introduction/sql.mdx index bd5d0717b..24d497bbe 100644 --- a/src/content/doc-surrealdb/introduction/sql.mdx +++ b/src/content/doc-surrealdb/introduction/sql.mdx @@ -86,7 +86,7 @@ For more in-depth explanations of SurrealDB concepts, see the [concepts page](/d join - record links, embedding and graph relations + record links, embedding and graph relations diff --git a/src/content/doc-surrealql/datamodel/records.mdx b/src/content/doc-surrealql/datamodel/records.mdx index 50c768550..4408f9876 100644 --- a/src/content/doc-surrealql/datamodel/records.mdx +++ b/src/content/doc-surrealql/datamodel/records.mdx @@ -88,7 +88,7 @@ SELECT friends.friends.friends.name FROM person:tobie; ## Next steps -You've now seen how to create records using randomly generated ids, or specific record ids. This is just the beginning! The power and flexibility which is possible with the remote record fetching functionality within queries opens up a whole new set of possibilities for storing and querying traditional data, and connected datasets. Take a look at the next chapter to understand how futures can be used to dynamically compute values only when retrieved. +You've now seen how to create records using randomly generated ids, or specific record ids. This is just the beginning! The power and flexibility which is possible with the remote record fetching functionality within queries opens up a whole new set of possibilities for storing and querying traditional data, and connected datasets. The next page follows up with a feature available in SurrealDB since version 2.2.0: the ability to use record links in a bidirectional manner thanks to reference tracking. Also check out this explainer video on using record links in SurrealDB: diff --git a/src/content/doc-surrealql/statements/define/indexes.mdx b/src/content/doc-surrealql/statements/define/indexes.mdx index c528dda14..6d4a48363 100644 --- a/src/content/doc-surrealql/statements/define/indexes.mdx +++ b/src/content/doc-surrealql/statements/define/indexes.mdx @@ -32,6 +32,7 @@ DEFINE INDEX [ OVERWRITE | IF NOT EXISTS ] @name ON [ TABLE ] @table [ FIELDS | ``` ## Index Types + SurrealDB offers a range of indexing capabilities designed to optimize data retrieval and search efficiency. ### Unique Index @@ -108,6 +109,7 @@ CREATE user:2 SET email = 'test@surrealdb.com' ``` ### Non-Unique Index + This allows for the indexing of attributes that may have non-unique values, facilitating efficient data retrieval. Non-unique indexes help index frequently appearing data in queries that do not require uniqueness, such as categorization tags or status indicators. Let's create a non-unique index for an age field on a user table. @@ -240,7 +242,7 @@ url="https://surrealist.app/mini?query=CREATE+pts%3A3+SET+point+%3D+%5B8%2C9%2C1 In the example above, you may notice the `EFC` and `M` parameters. These are optional to your query but are parameters of the [HNSW algorithm](https://arxiv.org/abs/1603.09320) and can be used to tune the index for better performance. At a glance - M (Max Connections per Element): -Defines the maximum number of bi-directional links (neighbors) per node in each layer of the graph, except for the lowest layer. This parameter controls the connectivity and overall structure of the network. Higher values of MM generally improve search accuracy but increase memory usage and construction time. +Defines the maximum number of bidirectional links (neighbors) per node in each layer of the graph, except for the lowest layer. This parameter controls the connectivity and overall structure of the network. Higher values of MM generally improve search accuracy but increase memory usage and construction time. - EFC (EF construction): Stands for "exploration factor during construction." This parameter determines the size of the dynamic list for the nearest neighbor candidates during the graph construction phase. A larger efConstruction value leads to a more thorough construction, improving the quality and accuracy of the search but increasing construction time. The default value is 150. diff --git a/src/content/doc-surrealql/statements/relate.mdx b/src/content/doc-surrealql/statements/relate.mdx index 0184ed9c5..e719098f9 100644 --- a/src/content/doc-surrealql/statements/relate.mdx +++ b/src/content/doc-surrealql/statements/relate.mdx @@ -17,13 +17,13 @@ Edges created using the RELATE statement are nearly identical to tables created Otherwise, edge tables behave like normal tables in terms of [updating](/docs/surrealql/statements/update), [defining a schema](/docs/surrealql/statements/define/table) or [indexes](/docs/surrealql/statements/define/indexes). -Another option for connecting data is using [record links](/docs/surrealql/datamodel/records). Record links consist of a field with record IDs that serve as uni-directional links. The key differences are that graph relations have the following benefits over record links: +Another option for connecting data is using [record links](/docs/surrealql/datamodel/records). Record links consist of a field with record IDs that serve as unidirectional links by default, or bidirectional links if reference tracking is used. The key differences are that graph relations have the following benefits over record links: - Graph relations are kept in a separate table as opposed to a field inside a record. -- Graph relations you to store data alongside the relationship. +- Graph relations allow you to store data alongside the relationship. - Graph relations have their own syntax that makes it easy to build and visualize edge queries. -Graph relations also offer built-in bi-directional querying and referential integrity. As of SurrealDB 2.2.0, record links also offer these two advantages if they are defined inside a [`DEFINE FIELD`](/docs/surrealql/statements/define/field) statement using the `REFERENCES` clause. For more information, see [the page on record references](/docs/surrealql/datamodel/references). +Graph relations offer built-in bidirectional querying and referential integrity. As of SurrealDB 2.2.0, record links also offer these two advantages if they are defined inside a [`DEFINE FIELD`](/docs/surrealql/statements/define/field) statement using the `REFERENCES` clause. For more information, see [the page on record references](/docs/surrealql/datamodel/references). ### Statement syntax @@ -140,7 +140,7 @@ DEFINE INDEX unique_relationships COLUMNS in, out UNIQUE; ``` -As edge tables are bi-directional by default, there is nothing stopping a query like the following in which an article writes a person instead of the other way around. +As edge tables are bidirectional by default, there is nothing stopping a query like the following in which an article writes a person instead of the other way around. ```surql RELATE article:on_sleep_and_sleeplessness->wrote->person:aristotle; diff --git a/src/content/doc-surrealql/statements/select.mdx b/src/content/doc-surrealql/statements/select.mdx index 58da796fa..65bb5bbce 100644 --- a/src/content/doc-surrealql/statements/select.mdx +++ b/src/content/doc-surrealql/statements/select.mdx @@ -521,7 +521,7 @@ SELECT * FROM ONLY person WHERE name = "Jaime" LIMIT 1; ## Connect targets using the FETCH clause -One of the most powerful functions in SurrealDB are the [record links](/docs/surrealql/datamodel/records) and [graph connections](/docs/surrealql/statements/relate). +Two of the most powerful features in SurrealDB are [record links](/docs/surrealql/datamodel/records) and [graph connections](/docs/surrealql/statements/relate). Instead of pulling data from multiple tables and merging that data together, SurrealDB allows you to traverse related records efficiently without needing to use JOINs. From b2d55a02ccf378a7663277b8914a37aa5d5138a7 Mon Sep 17 00:00:00 2001 From: Dave MacLeod <56599343+Dhghomon@users.noreply.github.com> Date: Fri, 3 Jan 2025 13:00:10 +0900 Subject: [PATCH 13/15] Pluralize publisher --- src/content/doc-surrealql/datamodel/references.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/content/doc-surrealql/datamodel/references.mdx b/src/content/doc-surrealql/datamodel/references.mdx index a5893440f..5e83c0fea 100644 --- a/src/content/doc-surrealql/datamodel/references.mdx +++ b/src/content/doc-surrealql/datamodel/references.mdx @@ -84,7 +84,7 @@ This can be fixed by changing the single field of type `references` to two field DEFINE FIELD comics ON person TYPE option>> REFERENCE; DEFINE FIELD products ON publisher TYPE option>> REFERENCE; DEFINE FIELD owners ON comic_book TYPE references; -DEFINE FIELD publisher ON comic_book TYPE references; +DEFINE FIELD publishers ON comic_book TYPE references; CREATE person:one, person:two SET comics = [comic_book:one]; CREATE publisher:one SET products = [comic_book:one, book:one]; @@ -100,7 +100,7 @@ SELECT * FROM comic_book; person:one, person:two ], - publisher: [ + publishers: [ publisher:one ], title: 'Loki, God of Stories' From ed965ad8e32082c70eca0edd311f5dbf3a650745 Mon Sep 17 00:00:00 2001 From: Dave MacLeod <56599343+Dhghomon@users.noreply.github.com> Date: Tue, 7 Jan 2025 13:51:55 +0900 Subject: [PATCH 14/15] Expand some more on advantages to graph links --- src/content/doc-surrealdb/reference-guide/graph_relations.mdx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/content/doc-surrealdb/reference-guide/graph_relations.mdx b/src/content/doc-surrealdb/reference-guide/graph_relations.mdx index 1a8fa2c98..80bb6faf8 100644 --- a/src/content/doc-surrealdb/reference-guide/graph_relations.mdx +++ b/src/content/doc-surrealdb/reference-guide/graph_relations.mdx @@ -156,8 +156,9 @@ Record links are preferred if: Graph links are preferred if: -* You want to create links without touching the database schema. +* You want to quickly create links without touching the database schema, or among multiple record types. For example, a single `RELATE person:one->wrote->[blog:one, book:one, comment:one]` is enough to create links between a `person` and three other record types, whereas using record links may be a more involved process involving several `DEFINE FIELD` statements. * You want to put together complex queries that take advantage of SurrealQL's expressive arrow syntax, like `->wrote->comment<-wrote<-person->wrote->comment FROM person`. +* You want to visualize your schema using Surrealist's designer view. Finally, graph links are not just preferred but almost certainly necessary if you need to keep metadata about the context in which a link is created. Take the following metadata for the examples above involving a user and its comments which contains information about a user's current location, operating system, and mood. Where does this data belong? From 132b81a8138b265f6e7f0ba11844d55ab2fbfa7b Mon Sep 17 00:00:00 2001 From: Dave MacLeod <56599343+Dhghomon@users.noreply.github.com> Date: Thu, 9 Jan 2025 14:49:19 +0900 Subject: [PATCH 15/15] +Interesting example of UNSET working like REJECT --- .../doc-surrealql/datamodel/references.mdx | 32 ++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/src/content/doc-surrealql/datamodel/references.mdx b/src/content/doc-surrealql/datamodel/references.mdx index 5e83c0fea..87996f993 100644 --- a/src/content/doc-surrealql/datamodel/references.mdx +++ b/src/content/doc-surrealql/datamodel/references.mdx @@ -360,7 +360,7 @@ CREATE house:one; CREATE utility:gas, utility:water SET connected_to = [house:one]; ``` -At this point, the `using` field on `house:one` automatically picks up the two references, +At this point, the `using` field on `house:one` automatically picks up the two references. Due to these references, the `house` record cannot be deleted. ```surql house:one.*; @@ -383,6 +383,8 @@ DELETE house:one; 'Cannot delete `house:one` as it is referenced by `utility:gas` with an ON DELETE REJECT clause' ``` +To delete the `house`, the `connected_to` references will first have to be removed. + ```surql UPDATE utility:gas SET connected_to -= house:one; UPDATE utility:water SET connected_to -= house:one; @@ -390,6 +392,34 @@ UPDATE utility:water SET connected_to -= house:one; DELETE house:one; ``` +Note that an `ON DELETE UNSET` for a required field is effectively the same as an `ON DELETE REJECT`. In both of the following two cases, a `person` that has any referencing `comment` records will not be able to be deleted. + +```surql +-- Non-optional field that attempts an UNSET when referencing 'person' is deleted +DEFINE FIELD author ON comment TYPE record REFERENCE ON DELETE UNSET; +LET $person = CREATE ONLY person; +CREATE comment SET text = "Cats are so much better at climbing UP a tree than down! Lol", author = $person.id; +DELETE person; + +-- Optional field which rejects the deletion of a referencing 'person' +DEFINE FIELD author ON comment TYPE option> REFERENCE ON DELETE REJECT; +LET $person = CREATE ONLY person; +CREATE comment SET text = "Cats are so much better at climbing UP a tree than down! Lol", author = $person.id; +DELETE person; +``` + +The error message in these two cases will differ, but the behaviour is the same. + +```surql +-------- Query -------- + +'An error occured while updating references for `person:jn7ux92gna61hxhc7fta`: Found NONE for field `author`, with record `comment:xrfbrrx2nw16l83io2cs`, but expected a record' + +-------- Query -------- + +'Cannot delete `person:3fm76xztvfab99eq780l` as it is referenced by `comment:ig0ogusbm64cier5ovv9` with an ON DELETE REJECT clause' +``` + ### ON DELETE THEN The `ON DELETE THEN` clause allows for custom logic when a reference is deleted. This clause includes a parameters called `$this` to refer to the record in question, and `$reference` for the reference.