Shape
Shape operations transform how results are returned. Use select() to define the output structure
and aggregate() for grouped/aggregated 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.
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