diff --git a/src/content/doc-surrealql/statements/upsert.mdx b/src/content/doc-surrealql/statements/upsert.mdx index d9178a93f..b161ba10f 100644 --- a/src/content/doc-surrealql/statements/upsert.mdx +++ b/src/content/doc-surrealql/statements/upsert.mdx @@ -10,10 +10,9 @@ import Since from '@components/Since.astro' -The `UPSERT` statement can be used to modify records in the database if they already exist. If the record does not exist, it will be created. - -This is different from the [`UPDATE`](/docs/surrealql/statements/update) statement, which will fail if the record does not exist. +The `UPSERT` statement can be used to modify records in the database if they already exist. If a specified record ID does not exist, it will be created. +This is different from the [`UPDATE`](/docs/surrealql/statements/update) statement, which will do nothing if a specified record ID does not exist. ### Statement syntax @@ -22,7 +21,7 @@ UPSERT [ ONLY ] @targets [ CONTENT @value | MERGE @value | PATCH @value - | SET @field = @value ... + | [ SET @field = @value, ... | UNSET @field, ... ] ] [ WHERE @condition ] [ RETURN NONE | RETURN BEFORE | RETURN AFTER | RETURN DIFF | RETURN @statement_param, ... ] @@ -30,56 +29,105 @@ UPSERT [ ONLY ] @targets [ PARALLEL ] ; ``` + ## Example usage -For example, if you want to UPSERT a record if it exists, or create it if it does not, you can use the `UPSERT` statement. +If you want to update a record if it exists, or create it if it does not, you can use the `UPSERT` statement with a specific record ID. ```surql --- UPSERT or create a record with a specific numeric id -UPSERT person:100 SET name = 'Tobie', company = 'SurrealDB', skills = ['Rust', 'Go', 'JavaScript']; +-- Update or create a record with a specific numeric id +UPSERT person:100 SET + name = 'Tobie', + company = 'SurrealDB', + skills = ['Rust', 'Go', 'JavaScript']; ``` -The `UPSERT` statement can be used to modify records in the database if they already exist. If the record does not exist, it will be created. -In the case where the record ID isn't specified, any exisiting records in the table will be upserted. For example, the following query will UPSERT all records in the `person` table: +In the case where the record ID isn't specified, any existing records in the table will be updated. For example, the following query will update all records in the `person` table but will not create any new ones. ```surql -- UPSERT all records in a table -- The skills field is an array. The += operator alone is enough for SurrealDB to infer the type -UPSERT person SET skills += 'breathing'; -``` - -The `UPSERT` statement supports conditional matching using the `WHERE` clause. For example, the following query will upsert the record with the specified ID only if the `name` field is equal to 'Tobie': - -```surql --- UPSERT a record with a specific numeric id only if the name is 'Tobie' -UPSERT person:100 SET name = 'Tobie', company = 'SurrealDB', skills = ['Rust', 'Go', 'JavaScript'] WHERE name = 'Tobie'; +UPSERT person SET skills -= 'breathing'; ``` ## Using ONLY clause +The `ONLY` clause can be used to return a single record instead of an array of records. + ```surql -- UPSERT just a single record -- Using the ONLY keyword, just an object for the record in question will be returned. -- This, instead of an array with a single object. -UPSERT ONLY person:tobie SET name = 'Tobie', company = 'SurrealDB', skills = ['Rust', 'Go', 'JavaScript']; +UPSERT ONLY person:tobie SET + name = 'Tobie', + company = 'SurrealDB', + skills = ['Rust', 'Go', 'JavaScript']; +``` + +## Type inference when using UPSERT + +The `+=` operator in the following query is enough for SurrealDB to infer that the `interests` field must be an `array`. + +```surql +-- UPSERT a document and remove a tag from an array +UPSERT person:tobie SET interests += 'Java'; ``` +Type inference will also work with a numeric value such as the `click_count` field below, in which case it will infer the field to be of type `int` with a default value of 0. ```surql -- UPSERT a document and increment a numeric value UPSERT webpage:home SET click_count += 1; +``` --- UPSERT a document and remove a tag from an array -UPSERT person:tobie SET interests -= 'Java'; +Creating a record by default makes the `UPSERT` statement an ideal way to manage an incrementing field. + +```surql +UPSERT event_for:[time::now().format("%Y-%m-%d")] SET + number += 1; ``` + +```bash title="Possible output" +[ + { + id: event_for:[ + '2024-09-18' + ], + number: 1 + } +] +``` + +Doing the same with an `UPDATE` statement would require much more manual work. + +```surql +IF (SELECT * FROM event_for:[time::now().format("%Y-%m-%d")]).is_empty() { + CREATE event_for:[time::now().format("%Y-%m-%d")] SET number = 1; +} ELSE { + UPDATE event_for:[time::now().format("%Y-%m-%d")] SET number += 1; +}; +``` + ## Using WHERE clause -The `UPSERT` statement supports conditional matching of records using a `WHERE` clause. If the expression in the `WHERE` clause evaluates to true, then the respective record will be upserted. +The `UPSERT` statement supports conditional matching using the `WHERE` clause, effectively turning it into an `UPDATE` statement. For example, the following query will update the record with the specified ID only if the `name` field is equal to 'Tobie' and will not create it otherwise. + +```surql +-- UPSERT a record with a specific numeric id only if the name is 'Tobie' +UPSERT person:100 SET + name = 'Tobie', + company = 'SurrealDB', + skills = ['Rust', 'Go', 'JavaScript'] +WHERE name = 'Tobie'; +``` ```surql -- UPSERT all records which match the condition UPSERT city SET population = 9541000 WHERE name = 'London'; ``` + +## CONTENT clause + Instead of specifying record data using the `SET` clause, it is also possible to use the `CONTENT` keyword to specify the record data using a SurrealQL object. ```surql @@ -141,7 +189,7 @@ The `UPSERT` statement supports bulk upsert, which allows multiple records to be UPSERT person CONTENT [ {id: r"person:jaime", name: "Jaime", surname: "Morgan Hitchcock"}, {id: "tobie", name: "Tobie", surname: "Morgan Hitchcock"}, - ... 1000 more records + -- ... 1000 more records ] ```