LiteGraph native graph query is a Cypher/GQL-inspired query profile with LiteGraph-native semantics. It is graph scoped: every query executes within one tenant and one graph. It is intended for concise graph reads, traversals, supplied-vector search, and graph child object mutations over nodes, edges, labels, tags, and vectors.
The language is not named LiteQL. Use "LiteGraph native graph query" in code and docs until a separate naming decision changes that.
Queries execute through:
- C# SDK:
client.Query.Execute(tenantGuid, graphGuid, request) - REST:
POST /v1.0/tenants/{tenantGuid}/graphs/{graphGuid}/query - MCP:
graph/querytool over HTTP, TCP, and WebSocket transports - Console:
lgcommand throughLiteGraphConsole
Every request uses this shape:
{
"Query": "MATCH (n:Person) WHERE n.data.age >= $age RETURN n LIMIT 10",
"Parameters": {
"age": 21
},
"MaxResults": 100,
"TimeoutSeconds": 30,
"IncludeProfile": false
}Inline literals are allowed for simple values, but parameters are preferred for user input, large arrays, objects, vectors, and values that should preserve JSON types.
The MCP graph/query tool accepts tenantGuid, graphGuid, and either a full request object/string with the shape above or the convenience fields query, parameters, maxResults, and timeoutSeconds. MCP execution is forwarded to the REST query endpoint so the same authentication, graph scoping, and credential-scope checks apply.
- A query executes within one tenant and one graph.
- Cross-tenant queries are not supported.
- Cross-graph queries are not supported.
- Query mutations can mutate graph child objects only: nodes, edges, labels, tags, and vectors.
- Query mutations must not update tenant, user, credential, admin, or graph metadata.
- Vector search uses supplied vectors. LiteGraph does not generate embeddings in this release.
Parameters are referenced with $name.
MATCH (n:Person) WHERE n.name = $name RETURN nParameter values preserve JSON-compatible types:
- strings
- numbers
- booleans
- null
- arrays
- objects
- vectors as numeric arrays
- GUIDs as strings or GUID values
Use parameters instead of string interpolation when values come from users or programs.
Missing parameters fail execution with a clear error naming the missing parameter. Unused parameters are accepted and ignored. Type-invalid parameters fail where the query needs a specific type; for example, a non-GUID value used with a guid predicate fails as an invalid GUID, and a non-array value used as a vector fails as an invalid vector array.
Comments are not part of the implemented language profile yet. Strip comments before sending query text.
Identifiers name variables, labels, fields, and procedure segments.
MATCH (a:Person)-[e:KNOWS]->(b:Person) RETURN a, e, bVariables are local to the query.
Supported literal forms:
'string'
"string"
42
3.14
true
false
nullObjects and arrays should be passed as parameters.
Match all nodes in the graph:
MATCH (n) RETURN nMatch nodes by label:
MATCH (n:Person) RETURN nFilter by GUID:
MATCH (n:Person) WHERE n.guid = $nodeGuid RETURN nFilter by name:
MATCH (n:Person) WHERE n.name = 'Ada' RETURN nFilter by nested data:
MATCH (n:Person) WHERE n.data.profile.age >= 30 RETURN nMatch directed edges:
MATCH (a)-[e]->(b) RETURN a, e, bMatch directed edges by edge label:
MATCH (a)-[e:KNOWS]->(b) RETURN a, e, bMatch source or target nodes by GUID:
MATCH (a)-[e:KNOWS]->(b) WHERE a.guid = $from RETURN a, e, b
MATCH (a)-[e:KNOWS]->(b) WHERE b.guid = $to RETURN a, e, bMatch edge fields:
MATCH (a)-[e:KNOWS]->(b) WHERE e.guid = $edgeGuid RETURN e
MATCH (a)-[e:KNOWS]->(b) WHERE e.name = 'Worked With' RETURN e
MATCH (a)-[e:KNOWS]->(b) WHERE e.data.kind = 'collaboration' RETURN eMatch source or target node data:
MATCH (a:Person)-[e:KNOWS]->(b:Person)
WHERE a.data.role = 'mathematician'
RETURN a, e, bFixed directed paths are supported:
MATCH (a:Person)-[e1:LINKS]->(b:Person)-[e2:LINKS]->(c:Person)
WHERE a.guid = $start
RETURN a, e1, b, e2, c
LIMIT 10Bounded variable-length directed paths are supported with *min..max syntax:
MATCH (a:Person)-[path:LINKS*1..3]->(c:Person)
WHERE a.guid = $start AND c.guid = $end
RETURN a, path, c
LIMIT 10The relationship variable for a variable-length segment returns a list of full
Edge objects for the matched path segment. The start and end variables return
full Node objects. Bounds are required in this release to keep traversal
execution predictable; unbounded * paths are rejected. The maximum bound is
32 hops.
MATCH SHORTEST returns only minimum-hop matches from the bounded candidate
set:
MATCH SHORTEST (a:Person)-[path:LINKS*1..5]->(c:Person)
WHERE a.guid = $start AND c.guid = $end
RETURN a, path, c
LIMIT 10Shortest-path execution still obeys the explicit upper bound. If multiple paths
have the same minimum hop count, all minimum-hop paths are eligible and LIMIT
controls the returned row count.
Top-level OPTIONAL MATCH is supported for read queries:
OPTIONAL MATCH (n:Person) WHERE n.name = $name RETURN n LIMIT 1
OPTIONAL MATCH (a:Person)-[e:KNOWS]->(b:Person) WHERE a.guid = $start RETURN a, e, b LIMIT 1When an optional match has no rows, LiteGraph returns one row with each returned
variable set to null. OPTIONAL MATCH does not support SET or DELETE
mutations in this release.
The current WHERE profile supports predicates joined with AND and OR.
NOT can be applied to a predicate or parenthesized predicate expression. AND
binds more tightly than OR; use parentheses when that is not the intended
grouping.
MATCH (n:Person)
WHERE n.data.role = $role AND n.data.profile.age >= 30
RETURN n
MATCH (n:Person)
WHERE n.name = 'Ada' OR n.name = 'Grace'
RETURN n
MATCH (n:Person)
WHERE (n.name = 'Ada' OR n.name = 'Grace') AND NOT n.data.role = 'engineer'
RETURN nOR and NOT predicates may scan candidate rows when they cannot be safely
pushed down to a repository lookup.
Equality is supported for:
guidnamedata.<field>tags.<key>
MATCH (n:Person) WHERE n.guid = $guid RETURN n
MATCH (n:Person) WHERE n.name = $name RETURN n
MATCH (n:Person) WHERE n.data.role = 'engineer' RETURN n
MATCH (n:Person) WHERE n.tags.field = 'math' RETURN nNumeric comparisons are supported for data.<field> values:
MATCH (n:Person) WHERE n.data.age > 30 RETURN n
MATCH (n:Person) WHERE n.data.age >= 30 RETURN n
MATCH (n:Person) WHERE n.data.age < 65 RETURN n
MATCH (n:Person) WHERE n.data.age <= 65 RETURN nBoth sides must be numeric when a numeric comparison operator is used.
String predicates are supported for name and data.<field> values:
MATCH (n:Person) WHERE n.name CONTAINS 'Ada' RETURN n
MATCH (n:Person) WHERE n.data.role STARTS WITH 'math' RETURN n
MATCH (a)-[e:KNOWS]->(b) WHERE e.name ENDS WITH 'With' RETURN eString comparisons are ordinal and case-sensitive in the current implementation.
IN tests whether a field equals any value in a literal list or parameter list.
MATCH (n:Person) WHERE n.name IN ['Ada', 'Grace'] RETURN n
MATCH (n:Person) WHERE n.guid IN [$adaGuid, $graceGuid] RETURN n
MATCH (n:Person) WHERE n.data.role IN $roles RETURN n
MATCH (n:Person) WHERE n.tags.field IN ['math', 'logic'] RETURN nWhen a parameter is used with IN, it must resolve to an array or enumerable
value. IN uses the same equality semantics as =, including GUID, Boolean,
numeric, and string equality.
Node and edge tags can be filtered with tags.<key> predicates. The tag key is
matched case-insensitively; the tag value uses the selected predicate operator.
MATCH (n:Person) WHERE n.tags.field = 'math' RETURN n
MATCH (a)-[e:KNOWS]->(b) WHERE e.tags.kind = 'historical' RETURN e
MATCH (a)-[e:KNOWS]->(b) WHERE a.tags.field = 'math' RETURN a, e, bTag predicates are evaluated through LiteGraph tag records and may scan candidate rows when no narrower seed predicate is available.
RETURN lists variables to include in each row.
MATCH (n:Person) RETURN n
MATCH (a)-[e:KNOWS]->(b) RETURN a, e, bNode rows return full Node objects. Edge rows return full Edge objects and can include source and target Node objects when those variables are returned. Label, tag, vector, and vector search rows also return full LiteGraph objects where applicable.
Aggregate RETURN items are supported for read-only MATCH node, edge, and
fixed-path queries. Aggregate returns cannot be mixed with graph variable
returns in the same query in this release.
Supported aggregate functions:
COUNT(*)COUNT(variable)andCOUNT(variable.field)SUM(variable.field)AVG(variable.field)MIN(variable.field)MAX(variable.field)
Examples:
MATCH (n:Person) RETURN COUNT(*) AS total
MATCH (n:Person) RETURN COUNT(n.data.profile.age) AS aged, AVG(n.data.profile.age) AS averageAge
MATCH (a)-[e:KNOWS]->(b) RETURN COUNT(e) AS edges, SUM(e.cost) AS totalCost
MATCH (a)-[e:KNOWS]->(b) WHERE a.tags.field = 'math' RETURN COUNT(*) AS paths, MAX(e.tags.kind) AS pathKindAggregate field paths support the same object fields used by ORDER BY plus
tags.<key> for node and edge tag values. SUM and AVG require numeric
values. COUNT(field) counts non-null field values. MIN and MAX use the
same ordering rules as ORDER BY.
Aggregate queries scan up to LIMIT or MaxResults and return one scalar row.
Use an explicit LIMIT or raise MaxResults when the aggregate needs to cover
a larger candidate set.
Query results include:
Profile: query language profile nameMutated: whether graph child objects were changedExecutionTimeMs: elapsed execution time in millisecondsExecutionProfile: optional parse, plan, execute, and total timings whenIncludeProfileis trueWarnings: planner or execution warningsPlan: compact plan summaryRows: result rows keyed by return variableNodes,Edges,Labels,Tags,Vectors,VectorSearchResults: typed object listsRowCount: number of result rows
The plan summary includes the query kind, mutation/vector/order/limit flags, estimated relative cost, and repository seed information when a predicate can start from a narrow repository read.
Set IncludeProfile to true when a caller needs phase timings for debugging or optimization:
{
"Query": "MATCH (n:Person) WHERE n.name = $name RETURN n LIMIT 10",
"Parameters": {
"name": "Ada Lovelace"
},
"IncludeProfile": true
}When enabled, ExecutionProfile contains:
ParseTimeMsPlanTimeMsExecuteTimeMsTotalTimeMs
Limit result rows:
MATCH (n:Person) RETURN n LIMIT 25Order returned rows:
MATCH (n:Person) RETURN n ORDER BY n.name ASC LIMIT 10
MATCH (n:Person) RETURN n ORDER BY n.data.profile.age DESC LIMIT 10Supported object sort fields:
- node:
guid,name,data.<field> - edge:
guid,name,cost,data.<field> - label:
guid,label - tag:
guid,key,value - vector:
guid,model,content,dimensionality - vector search result:
score,distance,innerProduct
When ORDER BY is present, LiteGraph scans up to MaxResults, sorts those rows, and then applies LIMIT.
Create a node:
CREATE (n:Person { name: $name, data: $data }) RETURN nSupported node properties:
namedata
The label in (n:Person) is assigned to the created node.
Create an edge:
CREATE ()-[e:KNOWS { from: $from, to: $to, name: $name, data: $data }]->() RETURN eSupported edge properties:
fromorfromGuidtoortoGuidnamedata
The label in [e:KNOWS] is assigned to the created edge.
Create a label object:
CREATE LABEL l { nodeGuid: $node, label: 'Scientist' } RETURN l
CREATE LABEL l { edgeGuid: $edge, label: 'RELATED_TO' } RETURN lSupported properties:
nodeGuidedgeGuidlabel
Create a tag object:
CREATE TAG t { nodeGuid: $node, key: 'field', value: 'math' } RETURN t
CREATE TAG t { edgeGuid: $edge, key: 'source', value: 'archive' } RETURN tSupported properties:
nodeGuidedgeGuidkeyvalue
Create a vector object with supplied embeddings:
CREATE VECTOR v {
nodeGuid: $node,
model: 'touchstone-query',
embeddings: $embedding,
content: 'Ada vector'
} RETURN vSupported properties:
nodeGuidedgeGuidmodelcontentembeddingsorvectors
Update a node by GUID:
MATCH (n:Person) WHERE n.guid = $node SET n.name = $name, n.data = $data RETURN nSupported node SET properties:
namedata
Update an edge by GUID:
MATCH ()-[e:LINKS]->() WHERE e.guid = $edge SET e.name = $name, e.cost = 7 RETURN eSupported edge SET properties:
namedatacost
Delete an edge by GUID:
MATCH ()-[e:LINKS]->() WHERE e.guid = $edge DELETE e RETURN eDelete a node by GUID:
MATCH (n:Person) WHERE n.guid = $node DELETE n RETURN nUpdate label:
MATCH LABEL l WHERE l.guid = $label SET l.label = $value RETURN lUpdate tag:
MATCH TAG t WHERE t.guid = $tag SET t.value = $value RETURN tUpdate vector:
MATCH VECTOR v WHERE v.guid = $vector SET v.content = $content, v.embeddings = $embedding RETURN vDelete objects:
MATCH LABEL l WHERE l.guid = $label DELETE l RETURN l
MATCH TAG t WHERE t.guid = $tag DELETE t RETURN t
MATCH VECTOR v WHERE v.guid = $vector DELETE v RETURN vMutation queries for labels, tags, and vectors require a GUID equality predicate in this release.
Search nodes with a supplied vector:
CALL litegraph.vector.searchNodes($embedding) YIELD node, score RETURN node, score LIMIT 5Other procedure names reserved by the parser:
CALL litegraph.vector.searchEdges($embedding) YIELD edge, score RETURN edge, score LIMIT 5
CALL litegraph.vector.searchGraph($embedding) YIELD result RETURN result LIMIT 5Node, edge, and graph vector search all use supplied embeddings. Graph vector search is still scoped to the one graph selected for the query session, even though lower-level vector APIs can search across a tenant. Embedding generation is outside the query language.
When graph vector indexing is enabled, node vector search uses the configured LiteGraph vector index for eligible searches. Searches with labels, tags, or expression filters may fall back to the repository implementation.
Return variables supported by vector search:
nodeornedgeoregraphorgscoredistanceinnerProductresult
Parser errors include line and column information. Execution errors describe unsupported query clauses, unsupported fields, missing parameters, invalid GUID values, nonnumeric comparison operands, and unsupported return variables.
Use these scenarios when comparing native query execution to equivalent REST or SDK multi-call sequences:
- one-hop edge expansion from a known source node:
MATCH (a)-[e:LINKS]->(b) WHERE a.guid = $start RETURN a, e, b LIMIT 100 - fixed two-hop traversal:
MATCH (a)-[e1:LINKS]->(b)-[e2:LINKS]->(c) WHERE a.guid = $start RETURN a, e1, b, e2, c LIMIT 100 - bounded variable-length traversal:
MATCH (a)-[path:LINKS*1..3]->(c) WHERE a.guid = $start RETURN a, path, c LIMIT 100 - data-filtered node lookup:
MATCH (n:Person) WHERE n.data.profile.age >= $age RETURN n LIMIT 100 - supplied-vector search:
CALL litegraph.vector.searchNodes($embedding) YIELD node, score RETURN node, score LIMIT 10
For each benchmark, record total elapsed time, repository operation count when profiling is enabled, returned row count, graph size, and whether vector indexes are enabled.
The current language profile does not yet include:
- unbounded variable-length paths
- query chaining across multiple
MATCH/OPTIONAL MATCHclauses - vector-index-aware planning beyond the current supplied-vector search path
SQLite and PostgreSQL provider execution are covered by the storage/query layers.
These examples are parser-covered in the shared automated suite.
Match all nodes:
MATCH (n) RETURN nMatch nodes by label:
MATCH (n:Person) RETURN nFind a node by GUID:
MATCH (n:Person) WHERE n.guid = $nodeGuid RETURN nFind a person by name:
MATCH (n:Person) WHERE n.name = $name RETURN n LIMIT 1Find people by nested numeric data:
MATCH (n:Person) WHERE n.data.profile.age >= 30 RETURN nMatch directed edges:
MATCH (a)-[e]->(b) RETURN a, e, bFind collaborations from a source node:
MATCH (a)-[e:KNOWS]->(b) WHERE a.guid = $from RETURN a, e, b LIMIT 25Find collaborations to a target node:
MATCH (a)-[e:KNOWS]->(b) WHERE b.guid = $to RETURN a, e, b LIMIT 25Find an edge by GUID:
MATCH (a)-[e:KNOWS]->(b) WHERE e.guid = $edgeGuid RETURN eFind edges by data:
MATCH (a)-[e:KNOWS]->(b) WHERE e.data.kind = 'collaboration' RETURN eFind a fixed two-hop path:
MATCH (a:Person)-[e1:LINKS]->(b:Person)-[e2:LINKS]->(c:Person)
WHERE a.guid = $start
RETURN a, e1, b, e2, c
LIMIT 10Find bounded variable-length paths:
MATCH (a:Person)-[path:LINKS*1..3]->(c:Person)
WHERE a.guid = $start AND c.guid = $end
RETURN a, path, c
LIMIT 10Find shortest bounded paths:
MATCH SHORTEST (a:Person)-[path:LINKS*1..5]->(c:Person)
WHERE a.guid = $start AND c.guid = $end
RETURN a, path, c
LIMIT 10Return a null row for an absent optional match:
OPTIONAL MATCH (n:Person) WHERE n.name = $name RETURN n LIMIT 1Find people by role and age:
MATCH (n:Person)
WHERE n.data.role = 'mathematician' AND n.data.profile.age >= 30
RETURN n
ORDER BY n.name ASC
LIMIT 50Find people by Boolean and list predicates:
MATCH (n:Person)
WHERE (n.name = 'Ada' OR n.name = 'Grace') AND NOT n.data.role = 'engineer'
RETURN n
MATCH (n:Person)
WHERE n.name IN ['Ada', 'Grace']
RETURN nFind people or edges by tags:
MATCH (n:Person) WHERE n.tags.field = 'math' RETURN n
MATCH (a)-[e:KNOWS]->(b) WHERE e.tags.kind = 'historical' RETURN eCount and summarize matches:
MATCH (n:Person) RETURN COUNT(*) AS total
MATCH (n:Person) RETURN COUNT(n.data.profile.age) AS aged, AVG(n.data.profile.age) AS averageAge
MATCH (a)-[e:KNOWS]->(b) RETURN COUNT(e) AS edges, SUM(e.cost) AS totalCostCreate a node:
CREATE (n:Person { name: 'Ada', data: $data }) RETURN nCreate an edge:
CREATE ()-[e:KNOWS { from: $from, to: $to, name: $name, data: $data }]->() RETURN eCreate a label:
CREATE LABEL l { nodeGuid: $node, label: 'Scientist' } RETURN lCreate a tag:
CREATE TAG t { nodeGuid: $node, key: 'field', value: 'math' } RETURN tCreate a vector:
CREATE VECTOR v { nodeGuid: $node, model: 'touchstone-query', embeddings: $embedding, content: 'Ada vector' } RETURN vUpdate a node:
MATCH (n:Person) WHERE n.guid = $node SET n.data = $data RETURN nUpdate an edge:
MATCH ()-[e:LINKS]->() WHERE e.guid = $edge SET e.name = $name, e.cost = 7 RETURN eDelete an edge:
MATCH ()-[e:KNOWS]->() WHERE e.guid = $edge DELETE e RETURN eDelete a node:
MATCH (n:Person) WHERE n.guid = $node DELETE n RETURN nUpdate a label:
MATCH LABEL l WHERE l.guid = $label SET l.label = $value RETURN lUpdate a tag:
MATCH TAG t WHERE t.guid = $tag SET t.value = $value RETURN tUpdate a vector:
MATCH VECTOR v WHERE v.guid = $vector SET v.content = $content, v.embeddings = $embedding RETURN vDelete a label:
MATCH LABEL l WHERE l.guid = $label DELETE l RETURN lDelete a tag:
MATCH TAG t WHERE t.guid = $tag DELETE t RETURN tDelete a vector:
MATCH VECTOR v WHERE v.guid = $vector DELETE v RETURN vSearch node vectors:
CALL litegraph.vector.searchNodes($embedding) YIELD node, score RETURN node, score LIMIT 5Search edge vectors:
CALL litegraph.vector.searchEdges($embedding) YIELD edge, score RETURN edge, score LIMIT 5Search graph vectors:
CALL litegraph.vector.searchGraph($embedding) YIELD result RETURN result LIMIT 5