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:

TRON51 B
Offset (hex)Bytes (hex)Meaning
0054 52 4F 4Emagic TRON
044C 6E616D65txt "name"
095C 4772616365txt "Grace"
0F0F 0A 04000000 0900 0000map leaf, size 10: @4 → @9
197C 235F6772616365txt "#_grace"
210F 0A 19000000 0F00 0000map leaf, size 10: @19 → @F

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:

TRON418 B
Offset (hex)Bytes (hex)Meaning
00054 52 4F 4Emagic TRON
0045C 236C696E6Btxt "#link"
00A02 01000000000000 00i64 1
0130F 0A 04000000 0A00 0000map leaf, size 10: @4 → @A
01D7C 6D616E61676572txt "manager"
0250F 0A 1D000000 1300 0000map leaf, size 10: @1D → @13
02F3C 616765txt "age"
03302 24000000000000 00i64 36
03C0F 0A 2F000000 3300 0000map leaf, size 10: @2F → @33
0464C 726F6C65txt "role"
04B8C 656E67696E6565 72txt "engineer"
0540F 0A 46000000 4B00 0000map leaf, size 10: @46 → @4B
05E4C 6E616D65txt "name"
0633C 416461txt "Ada"
0670F 0A 5E000000 6300 0000map leaf, size 10: @5E → @63
07107 16 20910000 2500 0000 3C000000 5400 0000 67000000map branch, size 22, depth 0 (root), slots 5, 8, 12, 15: @25 → @3C → @54 → @67
0875C 236C696E6Btxt "#link"
08D5C 235F616461txt "#_ada"
0930F 0A 87000000 8D00 0000map leaf, size 10: @87 → @8D
09D3C 616765txt "age"
0A102 29000000000000 00i64 41
0AA0F 0A 9D000000 A100 0000map leaf, size 10: @9D → @A1
0B46C 6D656E746F72txt "mentor"
0BB0F 0A B4000000 9300 0000map leaf, size 10: @B4 → @93
0C54C 726F6C65txt "role"
0CA8C 656E67696E6565 72txt "engineer"
0D30F 0A C5000000 CA00 0000map leaf, size 10: @C5 → @CA
0DD4C 6E616D65txt "name"
0E23C 426F62txt "Bob"
0E60F 0A DD000000 E200 0000map leaf, size 10: @DD → @E2
0F007 16 00990000 AA00 0000 BB000000 D300 0000 E6000000map branch, size 22, depth 0 (root), slots 8, 11, 12, 15: @AA → @BB → @D3 → @E6
1063C 616765txt "age"
10A02 1D000000000000 00i64 29
1130F 0A 06010000 0A01 0000map leaf, size 10: @106 → @10A
11D4C 726F6C65txt "role"
1228C 64657369676E65 72txt "designer"
12B0F 0A 1D010000 2201 0000map leaf, size 10: @11D → @122
1354C 6E616D65txt "name"
13A2C 4379txt "Cy"
13D0F 0A 35010000 3A01 0000map leaf, size 10: @135 → @13A
14707 12 00910000 1301 0000 2B010000 3D01 0000map branch, size 18, depth 0 (root), slots 8, 12, 15: @113 → @12B → @13D
1594C 235F6379txt "#_cy"
15E0F 0A 59010000 4701 0000map leaf, size 10: @159 → @147
1685C 235F626F62txt "#_bob"
16E0F 0A 68010000 F000 0000map leaf, size 10: @168 → @F0
1785C 235F616461txt "#_ada"
17E0F 0A 78010000 7100 0000map leaf, size 10: @178 → @71
18807 12 80210000 5E01 0000 6E010000 7E01 0000map branch, size 18, depth 0 (root), slots 7, 8, 13: @15E → @16E → @17E

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.

TRON401 B
Offset (hex)Bytes (hex)Meaning
00054 52 4F 4Emagic TRON
0042C 3F65txt "?e"
0070E 0D 00 0100 010000 00 04000000array leaf, size 13, shift 0, bitmap 0001, count 1 (root): @4
0142C 3F65txt "?e"
0174C 6E616D65txt "name"
01C3C 416461txt "Ada"
0200E 15 00 0700 030000 00 14000000 170000 00 1C000000array leaf, size 21, shift 0, bitmap 0007, count 3 (root): @14 → @17 → @1C
0352C 3F65txt "?e"
0383C 616765txt "age"
03C2C 3F76txt "?v"
03F0E 15 00 0700 030000 00 35000000 380000 00 3C000000array leaf, size 21, shift 0, bitmap 0007, count 3 (root): @35 → @38 → @3C
0540E 11 00 0300 020000 00 20000000 3F0000 00array leaf, size 17, shift 0, bitmap 0003, count 2 (root): @20 → @3F
0651C 2Atxt "*"
0672C 3F76txt "?v"
06A02 02000000000000 00i64 2
0730E 15 00 0700 030000 00 65000000 670000 00 6A000000array leaf, size 21, shift 0, bitmap 0007, count 3 (root): @65 → @67 → @6A
0887C 646F75626C6564txt "doubled"
0900F 0A 88000000 7300 0000map leaf, size 10: @88 → @73
09A7C 6D697373696E67txt "missing"
0A28C 2E756E6B6E6F77 6Etxt ".unknown"
0AB0F 0A 9A000000 A200 0000map leaf, size 10: @9A → @A2
0B53C 77686Ftxt "who"
0B95C 2E6E616D65txt ".name"
0BF0F 0A B5000000 B900 0000map leaf, size 10: @B5 → @B9
0C907 0E 06000000 AB00 0000 BF000000map branch, size 14, depth 1, slots 1, 2: @AB → @BF
0D74C 696E666Ftxt "info"
0DC0F 0A D7000000 9000 0000map leaf, size 10: @D7 → @90
0E64C 626F7373txt "boss"
0EBDC 2E6D616E616765 722E6E616D65txt ".manager.name"
0F90F 0A E6000000 EB00 0000map leaf, size 10: @E6 → @EB
10307 12 C0200000 C900 0000 DC000000 F900 0000map branch, size 18, depth 0 (root), slots 6, 7, 13: @C9 → @DC → @F9
1154C 726F6F74txt "root"
11A2C 3F65txt "?e"
11D0F 0A 15010000 1A01 0000map leaf, size 10: @115 → @11A
1276C 6669656C6473txt "fields"
12E0F 0A 27010000 0301 0000map leaf, size 10: @127 → @103
13807 0E 0A000000 1D01 0000 2E010000map branch, size 14, depth 0 (root), slots 1, 3: @11D → @12E
1465C 7768657265txt "where"
14C0F 0A 46010000 5400 0000map leaf, size 10: @146 → @54
1564C 66696E64txt "find"
15B0F 0A 56010000 0700 0000map leaf, size 10: @156 → @7
1657C 70726F6A656374txt "project"
16D0F 0A 65010000 3801 0000map leaf, size 10: @165 → @138
17707 12 0A040000 4C01 0000 5B010000 6D01 0000map branch, size 18, depth 0 (root), slots 1, 3, 10: @14C → @15B → @16D

The query selects Ada and gives one row:

TRON157 B
Offset (hex)Bytes (hex)Meaning
0054 52 4F 4Emagic TRON
047C 646F75626C6564txt "doubled"
0C02 48000000000000 00i64 72
150F 0A 04000000 0C00 0000map leaf, size 10: @4 → @C
1F7C 6D697373696E67txt "missing"
2700nil
280F 0A 1F000000 2700 0000map leaf, size 10: @1F → @27
323C 77686Ftxt "who"
363C 416461txt "Ada"
3A0F 0A 32000000 3600 0000map leaf, size 10: @32 → @36
4407 0E 06000000 2800 0000 3A000000map branch, size 14, depth 1, slots 1, 2: @28 → @3A
524C 696E666Ftxt "info"
570F 0A 52000000 1500 0000map leaf, size 10: @52 → @15
614C 626F7373txt "boss"
665C 4772616365txt "Grace"
6C0F 0A 61000000 6600 0000map leaf, size 10: @61 → @66
7607 12 C0200000 4400 0000 57000000 6C00 0000map branch, size 18, depth 0 (root), slots 6, 7, 13: @44 → @57 → @6C
880E 0D 00 0100 010000 00 76000000array leaf, size 13, shift 0, bitmap 0001, count 1 (root): @76

Field kinds

The value determines the field kind.

ValueKindResult
Text that starts with .PathReads that field of the root entity
An objectFieldsA nested shape with its own fields
Anything elseExpressionAn 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.

TRON324 B
Offset (hex)Bytes (hex)Meaning
00054 52 4F 4Emagic TRON
0042C 3F65txt "?e"
0070E 0D 00 0100 010000 00 04000000array leaf, size 13, shift 0, bitmap 0001, count 1 (root): @4
0142C 3F65txt "?e"
0174C 6E616D65txt "name"
01C3C 416461txt "Ada"
0200E 15 00 0700 030000 00 14000000 170000 00 1C000000array leaf, size 21, shift 0, bitmap 0007, count 3 (root): @14 → @17 → @1C
0352C 3F65txt "?e"
0383C 616765txt "age"
03C2C 3F76txt "?v"
03F0E 15 00 0700 030000 00 35000000 380000 00 3C000000array leaf, size 21, shift 0, bitmap 0007, count 3 (root): @35 → @38 → @3C
0542C 3F65txt "?e"
0574C 6E616D65txt "name"
05C2C 3F6Etxt "?n"
05F0E 15 00 0700 030000 00 54000000 570000 00 5C000000array leaf, size 21, shift 0, bitmap 0007, count 3 (root): @54 → @57 → @5C
0740E 15 00 0700 030000 00 20000000 3F0000 00 5F000000array leaf, size 21, shift 0, bitmap 0007, count 3 (root): @20 → @3F → @5F
0896C 666F726D6174txt "format"
0908C 7B7D206973207B 7Dtxt "{} is {}"
0992C 3F6Etxt "?n"
09C2C 3F76txt "?v"
09F0E 19 00 0F00 040000 00 89000000 900000 00 99000000 9C0000 00array leaf, size 25, shift 0, bitmap 000F, count 4 (root): @89 → @90 → @99 → @9C
0B85C 6C6162656Ctxt "label"
0BE0F 0A B8000000 9F00 0000map leaf, size 10: @B8 → @9F
0C84C 726F6F74txt "root"
0CD2C 3F65txt "?e"
0D00F 0A C8000000 CD00 0000map leaf, size 10: @C8 → @CD
0DA6C 6669656C6473txt "fields"
0E10F 0A DA000000 BE00 0000map leaf, size 10: @DA → @BE
0EB07 0E 0A000000 D000 0000 E1000000map branch, size 14, depth 0 (root), slots 1, 3: @D0 → @E1
0F95C 7768657265txt "where"
0FF0F 0A F9000000 7400 0000map leaf, size 10: @F9 → @74
1094C 66696E64txt "find"
10E0F 0A 09010000 0700 0000map leaf, size 10: @109 → @7
1187C 70726F6A656374txt "project"
1200F 0A 18010000 EB00 0000map leaf, size 10: @118 → @EB
12A07 12 0A040000 FF00 0000 0E010000 2001 0000map branch, size 18, depth 0 (root), slots 1, 3, 10: @FF → @10E → @120
TRON51 B
Offset (hex)Bytes (hex)Meaning
0054 52 4F 4Emagic TRON
045C 6C6162656Ctxt "label"
0A9C 41646120697320 3336txt "Ada is 36"
140F 0A 04000000 0A00 0000map leaf, size 10: @4 → @A
1E0E 0D 00 0100 010000 00 14000000array leaf, size 13, shift 0, bitmap 0001, count 1 (root): @14

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/.

TRON100 B
Offset (hex)Bytes (hex)Meaning
0054 52 4F 4Emagic TRON
043C 77686Ftxt "who"
086C 2E6E616D652Etxt ".name."
0F0F 0A 04000000 0800 0000map leaf, size 10: @4 → @8
194C 726F6F74txt "root"
1E2C 3F65txt "?e"
210F 0A 19000000 1E00 0000map leaf, size 10: @19 → @1E
2B6C 6669656C6473txt "fields"
320F 0A 2B000000 0F00 0000map leaf, size 10: @2B → @F
3C07 0E 0A000000 2100 0000 32000000map branch, size 14, depth 0 (root), slots 1, 3: @21 → @32
4A7C 70726F6A656374txt "project"
520F 0A 4A000000 3C00 0000map leaf, size 10: @4A → @3C

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.

TRON277 B
Offset (hex)Bytes (hex)Meaning
00054 52 4F 4Emagic TRON
0042C 3F65txt "?e"
0070E 0D 00 0100 010000 00 04000000array leaf, size 13, shift 0, bitmap 0001, count 1 (root): @4
0142C 3F65txt "?e"
0174C 6E616D65txt "name"
01C3C 416461txt "Ada"
0200E 15 00 0700 030000 00 14000000 170000 00 1C000000array leaf, size 21, shift 0, bitmap 0007, count 3 (root): @14 → @17 → @1C
0352C 3F65txt "?e"
0383C 616765txt "age"
03C2C 3F76txt "?v"
03F0E 15 00 0700 030000 00 35000000 380000 00 3C000000array leaf, size 21, shift 0, bitmap 0007, count 3 (root): @35 → @38 → @3C
0540E 11 00 0300 020000 00 20000000 3F0000 00array leaf, size 17, shift 0, bitmap 0003, count 2 (root): @20 → @3F
0653C 77686Ftxt "who"
0695C 2E6E616D65txt ".name"
06F0F 0A 65000000 6900 0000map leaf, size 10: @65 → @69
0794C 726F6F74txt "root"
07E2C 3F65txt "?e"
0810F 0A 79000000 7E00 0000map leaf, size 10: @79 → @7E
08B6C 6669656C6473txt "fields"
0920F 0A 8B000000 6F00 0000map leaf, size 10: @8B → @6F
09C07 0E 0A000000 8100 0000 92000000map branch, size 14, depth 0 (root), slots 1, 3: @81 → @92
0AA5C 7768657265txt "where"
0B00F 0A AA000000 5400 0000map leaf, size 10: @AA → @54
0BA4C 66696E64txt "find"
0BF0F 0A BA000000 0700 0000map leaf, size 10: @BA → @7
0C9AC 726573756C744D 6F6465txt "resultMode"
0D46C 6F626A656374txt "object"
0DB0F 0A C9000000 D400 0000map leaf, size 10: @C9 → @D4
0E57C 70726F6A656374txt "project"
0ED0F 0A E5000000 9C00 0000map leaf, size 10: @E5 → @9C
0F707 16 0A060000 B000 0000 BF000000 DB00 0000 ED000000map branch, size 22, depth 0 (root), slots 1, 3, 9, 10: @B0 → @BF → @DB → @ED

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.

TRON336 B
Offset (hex)Bytes (hex)Meaning
00054 52 4F 4Emagic TRON
0042C 3F65txt "?e"
0070E 0D 00 0100 010000 00 04000000array leaf, size 13, shift 0, bitmap 0001, count 1 (root): @4
0142C 3F65txt "?e"
0174C 6E616D65txt "name"
01C3C 416461txt "Ada"
0200E 15 00 0700 030000 00 14000000 170000 00 1C000000array leaf, size 21, shift 0, bitmap 0007, count 3 (root): @14 → @17 → @1C
0352C 3F65txt "?e"
0383C 616765txt "age"
03C2C 3F76txt "?v"
03F0E 15 00 0700 030000 00 35000000 380000 00 3C000000array leaf, size 21, shift 0, bitmap 0007, count 3 (root): @35 → @38 → @3C
0540E 11 00 0300 020000 00 20000000 3F0000 00array leaf, size 17, shift 0, bitmap 0003, count 2 (root): @20 → @3F
0652C 3F76txt "?v"
0680E 0D 00 0100 010000 00 65000000array leaf, size 13, shift 0, bitmap 0001, count 1 (root): @65
0754C 73697A65txt "size"
07A02 01000000000000 00i64 1
0830F 0A 75000000 7A00 0000map leaf, size 10: @75 → @7A
08D3C 77686Ftxt "who"
0915C 2E6E616D65txt ".name"
0970F 0A 8D000000 9100 0000map leaf, size 10: @8D → @91
0A14C 726F6F74txt "root"
0A62C 3F65txt "?e"
0A90F 0A A1000000 A600 0000map leaf, size 10: @A1 → @A6
0B36C 6669656C6473txt "fields"
0BA0F 0A B3000000 9700 0000map leaf, size 10: @B3 → @97
0C407 0E 0A000000 A900 0000 BA000000map branch, size 14, depth 0 (root), slots 1, 3: @A9 → @BA
0D25C 7768657265txt "where"
0D80F 0A D2000000 5400 0000map leaf, size 10: @D2 → @54
0E24C 66696E64txt "find"
0E70F 0A E2000000 0700 0000map leaf, size 10: @E2 → @7
0F17C 6F726465724279txt "orderBy"
0F90F 0A F1000000 6800 0000map leaf, size 10: @F1 → @68
1034C 70616765txt "page"
1080F 0A 03010000 8300 0000map leaf, size 10: @103 → @83
11207 0E 00280000 F900 0000 08010000map branch, size 14, depth 1, slots 11, 13: @F9 → @108
1207C 70726F6A656374txt "project"
1280F 0A 20010000 C400 0000map leaf, size 10: @120 → @C4
13207 16 2A040000 D800 0000 E7000000 1201 0000 28010000map branch, size 22, depth 0 (root), slots 1, 3, 5, 10: @D8 → @E7 → @112 → @128

Error

Invalid_Page

A projection reads the current document of each entity, so project with a temporal read is also an error.

Run it

database query · query run.