Querying the Graph
The graph query interface is a fluent C# API for traversing and querying the knowledge graph. The full interface is available inside Custom Endpoints and the Shell via the Q() / Query() global helpers. A subset is available in Data Connectors via graph.QueryAsync().
For the complete method reference, see Graph Query Language. This page covers the most common patterns and how to read node properties.
Using the Query Interface
In Endpoints and the Shell
The Q() helper creates a new query. Chain methods to build the pipeline, then either return the result directly or materialize it to C# objects for further logic.
// Return results directly from an endpoint
return Q().StartAt(N.SupportCase.Type)
.SortByTimestamp(oldestFirst: false)
.Take(50)
.Emit("N");
// Iterate over results in code
foreach (var node in Q().StartAt(N.SupportCase.Type).AsEnumerable())
{
var summary = node.GetString(N.SupportCase.Summary);
}
// Count matching nodes
int total = Q().StartAt(N.SupportCase.Type)
.WhereString(N.SupportCase.Type, N.SupportCase.Status, "Open")
.Count();
In Data Connectors
Use graph.QueryAsync(), which accepts a lambda over the library IQuery (a subset) and returns a QueryResults object.
var response = await graph.QueryAsync(q =>
q.StartAt(nameof(Nodes.Device)).Take(10).Emit("N"));
var nodes = response.GetEmitted("N");
See Querying in Data Connectors for the full data connector query reference.
Materializing Results
When writing code inside an endpoint, you can choose how to materialize results depending on the use case.
Return directly from the endpoint
The Emit family of methods serializes results to the HTTP response. Use this when you want to return data from an endpoint.
| Method | Description |
|---|---|
Emit(string name, params string[] fields) |
Return matched nodes, optionally restricting fields. |
EmitWithEdges(string name, params string[] fields) |
Return nodes with their edge data. |
EmitWithScores(string name, params string[] fields) |
Return nodes with their relevance scores. |
EmitCount(string name) |
Return only the count of matched nodes. |
EmitUIDs(string name) |
Return only node UIDs. |
EmitSummary(string name) |
Return a structural graph summary (useful in the shell). |
EmitNeighborsSummary(string name) |
Return a summary of edges from the current node set. |
Materialize to C# objects (in-code use)
Use these when you need to work with results in code, not return them directly.
| Method | Return Type | Description |
|---|---|---|
AsEnumerable() |
IEnumerable<ReadOnlyNode> |
Lazy iteration without loading all nodes at once. |
AsUIDEnumerable() |
IEnumerable<UID128> |
UIDs only — no node content loaded. |
AsTypedUIDEnumerable() |
IEnumerable<TypedUID128> |
Typed UID + node type pairs. |
AsScoredUIDEnumerable() |
IEnumerable<ScoredUID> |
UIDs with relevance scores. |
ToList() |
List<ReadOnlyNode> |
Materialize all nodes into a list. |
ToUIDList() |
List<UID128> |
All UIDs as a list. |
ToScoredUIDList() |
List<ScoredUID> |
All scored UIDs as a list. |
ToJsonAsync() |
Task<string> |
Serialize results to a JSON string. |
Count() |
int |
Total count. |
Any() |
bool |
True if any results exist. |
// Lazy iteration (efficient for large sets)
foreach (var node in Q().StartAt(N.SupportCase.Type).AsEnumerable())
{
// process each node
}
// Materialize to a list
var recentCases = Q().StartAt(N.SupportCase.Type)
.SortByTimestamp(oldestFirst: false)
.Take(20)
.ToList();
// Check existence
bool hasOpen = Q().StartWhereString(N.SupportCase.Type, N.SupportCase.Status, "Open").Any();
Accessing Node Properties
Nodes returned from AsEnumerable(), ToList(), or inside a Where() predicate expose typed accessor methods.
| Data Type | Accessor | List Accessor |
|---|---|---|
| String | GetString(key) |
GetStringList(key) |
| Integer | GetInt(key) |
GetIntList(key) |
| Boolean | GetBool(key) |
GetBoolList(key) |
| Float | GetFloat(key) |
GetFloatList(key) |
| Double | GetDouble(key) |
GetDoubleList(key) |
| Long | GetLong(key) |
GetLongList(key) |
| DateTime | GetTime(key) |
GetTimeList(key) |
| UID | GetUID128(key) |
GetUID128List(key) |
| Dynamic | node[key] |
— |
Use auto-generated constants (e.g. N.SupportCase.Content) instead of raw strings to avoid typos:
foreach (var node in Q().StartAt(N.SupportCase.Type).AsEnumerable())
{
var id = node.GetString(N.SupportCase.Id);
var summary = node.GetString(N.SupportCase.Summary);
var time = node.GetTime(N.SupportCase.Time);
}
Common Patterns
Pagination
class PageRequest { public int Page { get; set; } }
const int pageSize = 50;
var req = Body.FromJson<PageRequest>();
return Q().StartAt(N.Part.Type)
.Skip(req.Page * pageSize)
.Take(pageSize)
.Emit();
Filter by related entity
var deviceUID = Node.GetUID(N.Device.Type, "MacBook Air");
return Q().StartAt(N.SupportCase.Type)
.IsRelatedTo(deviceUID)
.SortByTimestamp(oldestFirst: false)
.Take(50)
.Emit("N");
Semantic similarity with graph filter
class Request { public string Query { get; set; } public string Manufacturer { get; set; } }
var req = Body.FromJson<Request>();
return Q().StartAtSimilarText(req.Query, nodeTypes: [N.SupportCase.Type], count: 500)
.IsRelatedTo(Node.GetUID(N.Manufacturer.Type, req.Manufacturer))
.EmitWithScores();
Set operations
// Union: combine two queries
var open = Q().StartWhereString(N.SupportCase.Type, N.SupportCase.Status, "Open");
var high = Q().StartWhereString(N.SupportCase.Type, N.SupportCase.Priority, "High");
return open.Union(high).Distinct().SortByTimestamp(oldestFirst: false).Emit("N");
Shell exploration
// Graph structure overview
return Q().EmitSummary();
// What edges does SupportCase have?
return Q().StartAt(N.SupportCase.Type).EmitNeighborsSummary();
// Analytics: count cases per device
return Q().StartAt(N.Device.Type).AsEnumerable()
.ToDictionary(
n => n.GetString(N.Device.Name),
n => Q().StartAt(n.UID).Out(N.SupportCase.Type).Count()
);
Next Steps
- Full method reference: Graph Query Language
- Search integration: Search Configuration
- Data connector queries: Querying in Data Connectors