Project
A query gives rows, and ordering arranges them.
project shapes each row into the document that the caller needs.
The caller receives that document without a second assembly step.
The examples start from Ada, Bob and Cy. They also add Grace as Ada's manager. A reference points to an existing entity, so create Grace first:
#_grace {name Grace}
The first commit returns Grace's ID, 1, in this fresh database. The next patch creates Ada, Bob and Cy with IDs 3, 4 and 5. Ada's manager references Grace:
#_ada {name Ada
role engineer
age 36
manager {#link 1}}
#_bob {name Bob
role engineer
age 41
mentor {#link #_ada}}
#_cy {name Cy
role designer
age 29}
Root and fields
project has root and fields members. root is an expression that gives the
entity to read for each row. fields is the shape of the output, and it cannot be
empty.
find [?e]
where [[?e name Ada]
[?e age ?v]]
project {root ?e
fields {who .name
boss .manager.name
missing .unknown
info {doubled [* ?v 2]}}}
The query selects Ada and gives one row:
[{who Ada
boss Grace
missing null
info {doubled 72}}]Field kinds
The value determines the field kind.
| Value | Kind | Result |
|---|---|---|
Text that starts with . | Path | Reads that field of the root entity |
| An object | Fields | A nested shape with its own fields |
| Anything else | Expression | An expression for each row |
A path follows entity references, so .manager.name reads the name of the
entity that manager refers to. A path that reaches nothing gives null
instead of an error, as .unknown does above.
A nested object gives a nested document. An expression reads the row's
variables, so info.doubled doubles ?v from the where clause.
Building text
An expression field builds text with format. The template
comes first, and each {} accepts the next argument.
find [?e]
where [[?e name Ada]
[?e age ?v]
[?e name ?n]]
project {root ?e
fields {label [format
'{} is {}'
?n
?v]}}
[{label 'Ada is 36'}]An argument is an expression, never a path. A path reads a field only as the
whole value of a field, so .name inside format gives the text .name.
The query above binds ?n in where, which is how a field of the root
entity reaches a template.
Names and paths
A field name cannot be empty, and it cannot start with $. Each segment of a
path must be a name, so .. and a trailing . are errors. A segment cannot
use the reserved array storage prefix stardust/list/.
project {root ?e
fields {who .name.}}
Error
Invalid_Project
The path .name. ends with an empty segment. .name reads that field, and
.manager.name follows the reference in manager to read a field of another
entity.
Result mode
project selects positional rows when the query does not have resultMode.
You can also set resultMode positional.
resultMode object and project give two shapes for one row. A query that
contains both gives an error.
find [?e]
where [[?e name Ada]
[?e age ?v]]
resultMode object
project {root ?e
fields {who .name}}
Error
Project_Result_Mode_Conflict
Project and page limits
A projected shape is not a page boundary, so project and page together are
an error.
find [?e]
where [[?e name Ada]
[?e age ?v]]
orderBy [?v]
page {size 1}
project {root ?e
fields {who .name}}
Error
Invalid_Page
A projection reads the current document of each entity, so project with a
temporal read is also an error. Queries covers the temporal
forms.