Skip to content

Commit

Permalink
Change headers to display in the menu
Browse files Browse the repository at this point in the history
  • Loading branch information
Dhghomon committed Jan 6, 2025
1 parent 070cf5d commit 587ef32
Showing 1 changed file with 32 additions and 36 deletions.
68 changes: 32 additions & 36 deletions src/content/doc-surrealql/datamodel/idioms.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@ Idioms in SurrealQL provide a powerful and flexible way to access and manipulate

An idiom is composed of a sequence of **parts** that define the path to a value within a record or data structure. Each part specifies how to navigate to the next piece of data. Idioms can be used in various parts of SurrealQL. The most common usecase is in data retrival queries such as `SELECT` statements, but they can also be used in the `WHERE` clause, `SET` clause, and more.

## Parts of an Idiom

An idiom is made up of one or more **parts**, each of which can be one of several types:

- [**Field**](#field-access): Access a field by name.
Expand All @@ -30,7 +28,7 @@ An idiom is made up of one or more **parts**, each of which can be one of severa

In this section, we'll explore each part in detail with examples to help you understand how to use idioms in SurrealQL.

### Field Access
## Field Access

Since SurrealDB is, at its core, a document database, each record is stored on an underlying key-value store storage engine, with the ability to store arbitrary arrays, objects, and many other types of data. To access a field in an object, use a dot `.` followed by the field name.

Expand Down Expand Up @@ -80,7 +78,7 @@ SELECT address.city FROM person;
```
In this example, `person.name` is an idiom that accesses the `name` field of the `person` record.

### Index Access
## Index Access

To access an element in an array by its index, use square brackets `[]` with the index inside. For example, let's say we have a `school` record with some student results.

Expand Down Expand Up @@ -142,7 +140,7 @@ SELECT results[0].score FROM student;

Here, `results[0].score` accesses the score of the first student in the `results` array.

### All Elements
## All Elements

To access all elements in an array or all fields in an object, use `.*`. This is useful when you want to access all the elements in an array or all the fields in an object.

Expand Down Expand Up @@ -189,13 +187,13 @@ The output for `INFO FOR TABLE person` includes an automatically generated defin
}
```

#### Using `.*` to return values
### Using `.*` to return values

<Since v="v2.1.0" />

The `.*` idiom in SurrealDB allows you to target all values in an object or all entries in an array. It can be used in various contexts such as querying, field definitions, and data manipulation. This section explains the behavior of `.*` with practical examples.

#### Accessing All Values in an Object
### Accessing all values in an object

When applied to an object, `.*` returns an array containing all the values of the object's properties.

Expand All @@ -211,7 +209,7 @@ When applied to an object, `.*` returns an array containing all the values of th

In this example, `{ a: 1, b: 2 }.*` extracts the values `1` and `2` from the object and returns them as an array.

##### Defining Fields with `.*`
#### Defining Fields with `.*`

You can define fields using `.*` to specify constraints or types for all properties within an object field.

Expand All @@ -233,7 +231,7 @@ CREATE test:1 SET obj.a = 'a';
Found 'a' for field `obj[*]`, with record `test:1`, but expected a number
```

##### Using `.*` in Different Contexts
#### Using `.*` in Different Contexts

Depending on where `.*` is used, it can have different effects on the order of operations.

Expand Down Expand Up @@ -317,7 +315,7 @@ SELECT * FROM { id: person:tobie, name: 'tobie' }.*;
```

### Last Element
## Last Element

Addionally to access the last element of an array, use `[$]`. Refereing to the `student` record above, we can access the last element of the `results` array using the following idiom:

Expand All @@ -336,7 +334,7 @@ SELECT results[$].score FROM student;

This idiom accesses the last element of the `score` array.

### Method chaining
## Method chaining

<Since v="v2.0.0" />

Expand Down Expand Up @@ -398,7 +396,7 @@ SELECT string::uppercase(name) FROM person;

To learn more about string method chaining in SurrealQL, see the [string functions](/docs/surrealql/functions/database/string#method-chaining) section.

### Graph Navigation
## Graph Navigation

SurrealDB can also be used in the context of graph databases, where data is stored and navigated using graph traversal idioms. The [`RELATE` statement](/docs/surrealql/statements/relate) is used to create relationships between records. This allows you to traverse related records efficiently without needing to pull data from multiple tables and merging that data together using SQL JOINs.

Expand Down Expand Up @@ -455,7 +453,7 @@ Explanation:
- `<->? AS involved_in`: Retrieves all relationships connected to Drake, regardless of direction, and aliases them as involved_in.


### Destructuring
## Destructuring

<Since v="v2.0.0" />

Expand Down Expand Up @@ -549,7 +547,7 @@ FROM explorer:drake;
]
```

#### Using aliases when destructuring
### Using aliases when destructuring

The keyword `AS` is necessary inside `SELECT` statements when [using an alias](/docs/surrealql/statements/select#basic-usage) (a new name for a field).

Expand Down Expand Up @@ -626,7 +624,7 @@ $town.{
};
```

#### Destructuring the current item in a SELECT query
### Destructuring the current item in a SELECT query

<Since v="v2.1.0" />

Expand Down Expand Up @@ -676,7 +674,7 @@ FROM planet)

Most importantly, however, the `@` operator is often necessary when using [recursive paths](#recursive-paths).

### Optional Parts
## Optional Parts

<Since v="v2.0.0" />

Expand All @@ -690,7 +688,7 @@ SELECT person.spouse?.name FROM person;

This idiom safely accesses `person.spouse.name` if `spouse` exists; otherwise, it returns `NONE`.

### Using Optional Parts
## Using Optional Parts

If some `person` records have a `spouse` field and others do not:

Expand All @@ -700,7 +698,7 @@ SELECT name, spouse?.name AS spouse_name FROM person;

This idiom will return `NONE` for `spouse_name` if the `spouse` field is not present.

### Recursive paths
## Recursive paths

<Since v="v2.1.0" />

Expand All @@ -717,7 +715,7 @@ person:tobie.{2}(->friends_with->person).name;

As the syntax of recursive queries tends to be complex to the untrained eye, this section will explain them in order of difficulty, beginning with what queries were necessary before recursive paths were added in SurrealDB version 2.1.

#### Overview
### Overview

Take the following example that creates one planet, two countries, two states/provinces in each of these countries, and two cities in each of those states/provinces. The `CREATE` statements are followed by `UPDATE` statements to set record links between them, and `RELATE` to create bidirectional graph relations between them.

Expand Down Expand Up @@ -854,7 +852,7 @@ FROM planet:earth;
]
```

#### Basics of recursive paths
### Basics of recursive paths

Using a recursive path allows you to instead set the number of steps to follow instead of manually typing. A recursive path is made by isolating `{}` braces in between two dots, inside which the number of steps is indicated.

Expand Down Expand Up @@ -907,7 +905,7 @@ planet:earth.{..}->has->(?);
]
```

#### Using () to provide instructions at each depth
### Using () to provide instructions at each depth

Parentheses can be added to a recursive query. To explain their use, consider the following example that attempts to traverse up to a depth of 3 and return the `name` of the records at that level.

Expand Down Expand Up @@ -962,7 +960,7 @@ planet:earth
.{name, id};
```

#### Using `@` to refer to the current record
### Using `@` to refer to the current record

The `@` symbol is used in recursive queries to refer to the current document. This is needed in recursive `SELECT` queries, as without it there is no way to know the context.

Expand All @@ -985,7 +983,7 @@ SELECT @.{1..3}(->has->(?)) AS cities FROM planet;
SELECT name.len() AS length FROM planet;
```

#### Using `{}` and `.@` to combine results
### Using `{}` and `.@` to combine results

Inside the structure of a recursive graph query, the `@` symbol is used in the form of `.@` at the end of a path to inform the database that this is the path to be repeated during the recursion. This allows not just the fields on the final depth of the query to be returned, but each one along the way as well.

Expand Down Expand Up @@ -1111,7 +1109,7 @@ SELECT @{1..4}(->knows->person).name AS names_2nds FROM person;
person:tobie.{1..5}(.friend).name;
```

#### Behaviour of recursive queries
### Behaviour of recursive queries

Recursive queries follow a few rules to determine how far to traverse and what to return. They are:

Expand All @@ -1121,7 +1119,7 @@ Recursive queries follow a few rules to determine how far to traverse and what t
* If it has already passed the minimum depth, it returns the last valid value.
* During each iteration, if it encounters an array value, all dead end values are automatically filtered out, ensuring no empty paths are included.

#### Filtering recursive fields
### Filtering recursive fields

Recursive syntax is not just useful in creating recursive queries, but parsing them as well. Take the following example that creates some `person` records, gives each of them two friends, and then traverses the `friends_with` graph for the first `person` records to find its friends, friends of friends, and friends of friends of friends. Since every level except the last contains another `connections` field, adding a `.{some_number}.connections` to a `RETURN` statement is all that is needed to drill down to a certain depth.

Expand Down Expand Up @@ -1166,23 +1164,23 @@ Possible output of the final query:
}
```

#### Collecting paths, collecting unique nodes, finding shortest path
### Collecting paths, collecting unique nodes, finding shortest path

<Since v="v2.2.0" />

SurrealDB has a number of built-in algorithms that allow recursive queries to collect all paths, all unique nodes, and to find the shortest path to a record. The syntax is as follows:
SurrealDB has a number of built-in algorithms that allow recursive queries to collect all paths, all unique nodes, and to find the shortest path to a record. These can be used by adding the following keywords to the recursive syntax specifying the depth to recurse:

* `{..+path}`: used to collect all walked paths.
* `{..+collect}`: used to collect all unique nodes walked.
* `{..+shortest=record:id}`: used to find the shortest path to a specified record id, such as `person:tobie` or `person:one`.

The originating (first) record is excluded from these paths. To include the first record, `+inclusive` can be added to the syntax above.
The originating (first) record is excluded from these paths by default. However, it can be included by adding `+inclusive` to the syntax above.

* `{..+path+inclusive}`
* `{..+collect+inclusive}`
* `{..+shortest=record:id+inclusive}`

To demonstrate the output of these three algorithms, take the following example showing a small network of friends. The network begins with `person:you`, followed by two friends (`person:friend1`, `person:friend2`), then three acquaintances known by these friends (`person:acquaintance1`, `person:acquaintance2`, `person:acquaintance3`), and finally a movie star (`person:star`) who is known by one of the acquaintances.
To demonstrate the output of these three algorithms, take the following example showing a small network of friends. The network begins with `person:you`, followed by two friends (`person:friend1`, `person:friend2`), then three acquaintances known by these friends (`person:acquaintance1`, `person:acquaintance2`, `person:acquaintance3`), and finally a movie star (`person:star`) who is known by only one of the acquaintances.

```surql
CREATE
Expand Down Expand Up @@ -1216,7 +1214,7 @@ person:you │ │ ▲
└───►person:acquaintance3─────────┘
```

To use these algorithms, follow them with the path that should be followed, in this case `->knows->person`.
After specifying an algorithm to use, such as `{..+path}`, add the path that should be followed, in this case `->knows->person`.

Adding `+path` will output all of the possible paths starting from `person:you`. As the output is fairly short, we can see that there are two ways to get from `person:one` to the movie star at `person:star`, one of which is one step shorter than the other.

Expand Down Expand Up @@ -1430,12 +1428,10 @@ person:you.{..+path}.knows;
person:you.{..+collect}.knows;
```

## Combining Idiom Parts
# Combining Idiom Parts

Idioms can combine multiple parts to navigate complex data structures seamlessly.

### Complex Example

Suppose we have the following data:

```surql title="Create a new person record"
Expand Down Expand Up @@ -1504,21 +1500,21 @@ SELECT friends[WHERE age > 18].name FROM person WHERE id = r'person:5';
]
```

## Notes on Idioms
# Notes on Idioms

- **Chaining**: Idioms can be chained to traverse deeply nested structures.
- **Performance**: Be mindful of performance when using complex idioms; indexing fields can help.
- **NONE Safety**: Use optional parts (`?`) to handle `NONE` or missing data gracefully.
- **Methods**: Leverage built-in methods for data manipulation within idioms.
- **Type Casting**: Use type casting if necessary to ensure data is in the correct format.

## Best Practices
# Best Practices

- **Use Destructuring**: When selecting multiple fields, destructuring improves readability.
- **Limit Optional Parts**: Use optional parts judiciously to avoid masking data issues.
- **Validate Data**: Ensure data conforms to expected structures, especially when dealing with optional fields.
- **Index Fields**: Index fields that are frequently accessed or used in `WHERE` clauses for better performance.

## Summary
# Summary

Idioms in SurrealQL are a powerful tool for navigating and manipulating data within your database. By understanding and effectively using idiom parts, you can write expressive and efficient queries that handle complex data structures with ease. Whether you're accessing nested fields, filtering arrays, or traversing graph relationships, idioms provide the flexibility you need to interact with your data seamlessly.

0 comments on commit 587ef32

Please sign in to comment.