Shape
Shape operations transform how results are returned. Use select() for the compatibility result
mapper, project() for an explicit SQL projection, map() for a final JavaScript transformation,
and aggregate() for grouped results.
select()
Section titled “select()”The select() method defines what data to return:
const results = await store .query() .from("Person", "p") .select((ctx) => ({ name: ctx.p.name, email: ctx.p.email, })) .execute();Parameters
Section titled “Parameters”.select(selectFunction)| Parameter | Type | Description |
|---|---|---|
selectFunction |
(ctx) => T |
Function that receives a context and returns the output shape |
The context provides typed access to all nodes and edges in the query via their aliases.
For new queries that need SQL composition, use project() and the typed expr helpers described in
Database Expressions. A projected query can become an
asRelation() for derived filtering, aggregation, distinctness, and set
operations. Use select() when you specifically need the compatibility JavaScript mapper.
Selection Patterns
Section titled “Selection Patterns”Full Node
Section titled “Full Node”Return all properties as an object:
.select((ctx) => ctx.p)
// Returns: { id, kind, name, email, ... }Specific Fields
Section titled “Specific Fields”Return only the fields you need:
.select((ctx) => ({ id: ctx.p.id, name: ctx.p.name, email: ctx.p.email,}))Node Metadata
Section titled “Node Metadata”Include system metadata fields:
.select((ctx) => ({ id: ctx.p.id, kind: ctx.p.kind, // "Person" version: ctx.p.version, // Optimistic concurrency version createdAt: ctx.p.createdAt, updatedAt: ctx.p.updatedAt,}))Multiple Nodes
Section titled “Multiple Nodes”Select from multiple nodes in a traversal:
const results = await store .query() .from("Person", "p") .traverse("worksAt", "e") .to("Company", "c") .select((ctx) => ({ person: ctx.p.name, company: ctx.c.name, role: ctx.e.role, // Edge property })) .execute();Nested Objects
Section titled “Nested Objects”Structure output with nested objects:
.select((ctx) => ({ employee: { id: ctx.p.id, name: ctx.p.name, }, company: { id: ctx.c.id, name: ctx.c.name, }, employment: { role: ctx.e.role, startDate: ctx.e.startDate, },}))Renamed Fields
Section titled “Renamed Fields”Rename fields in the output:
.select((ctx) => ({ personName: ctx.p.name, // Renamed from 'name' companyName: ctx.c.name, // Renamed from 'name' jobTitle: ctx.e.role, // Renamed from 'role'}))Type Inference
Section titled “Type Inference”TypeScript infers the result type from your selection:
// TypeScript infers: Array<{ name: string; email: string | undefined }>const results = await store .query() .from("Person", "p") .select((ctx) => ({ name: ctx.p.name, // string (required in schema) email: ctx.p.email, // string | undefined (optional in schema) })) .execute();
// Invalid property access caught at compile time:.select((ctx) => ({ invalid: ctx.p.nonexistent, // TypeScript error!}))Optional Traversal Results
Section titled “Optional Traversal Results”When using optionalTraverse(), accessed nodes and edges may be undefined:
const results = await store .query() .from("Person", "p") .optionalTraverse("worksAt", "e") .to("Company", "c") .select((ctx) => ({ person: ctx.p.name, company: ctx.c?.name, // May be undefined role: ctx.e?.role, // May be undefined })) .execute();aggregate()
Section titled “aggregate()”Use aggregate() with aggregate functions for grouped queries:
import { count, sum, avg, field } from "@nicia-ai/typegraph";
const stats = await store .query() .from("Person", "p") .traverse("worksAt", "e") .to("Company", "c") .groupBy("c", "name") .aggregate({ companyName: field("c", "name"), employeeCount: count("p"), totalSalary: sum("e", "salary"), avgSalary: avg("e", "salary"), }) .execute();See Aggregate for full aggregate documentation.
Selecting Path Information
Section titled “Selecting Path Information”With recursive traversals, include path and depth:
const results = await store .query() .from("Category", "cat") .traverse("parentCategory", "e") .recursive({ path: "pathIds", depth: "depth" }) .to("Category", "ancestor") .select((ctx) => ({ category: ctx.cat.name, ancestor: ctx.ancestor.name, path: ctx.pathIds, // Array of node IDs depth: ctx.depth, // Number of hops })) .execute();Temporal Metadata
Section titled “Temporal Metadata”When using temporal queries, access validity information:
const history = await store .query() .from("Article", "a") .temporal("includeEnded") .select((ctx) => ({ title: ctx.a.title, validFrom: ctx.a.validFrom, // When this version became valid validTo: ctx.a.validTo, // When superseded (undefined if current) version: ctx.a.version, // Version number })) .execute();Return Type
Section titled “Return Type”select() returns an ExecutableQuery that provides:
execute()- Run the query and get resultspaginate()- Cursor-based paginationstream()- Stream results for large datasetsfirst()- Get the first result or undefinedcount()- Count matching resultsexists()- Check if any results existtoAst()- Get the query ASTcompile()- Compile to SQL
Next Steps
Section titled “Next Steps”- Expressions - SQL projection and typed expression callbacks
- Relations - Compose explicit projected results
- Aggregate - Grouping and aggregate functions
- Order - Ordering and limiting results
- Execute - Running queries and pagination