Graph#
Concourse’s document-graph data model lets you store relationships between records and traverse them efficiently. Relationships are represented as Links — directional pointers from one record to another.
Linking Records#
Use the link method to create a directed relationship from a
source record to a destination record via a named key.
1 2 3 | |
1 2 | |
Links are directional. The example above creates a relationship from record 1 to record 100, but record 100 has no automatic back-reference to record 1.
Link to Multiple Destinations#
1 2 3 | |
Removing Links#
Use unlink to remove a relationship:
1 2 | |
1 2 | |
Link Queries#
You can query for records that link to a specific destination
using the LINKS_TO operator:
1 | |
1 2 3 | |
This returns all records whose employer key contains a link to
record 100.
Navigation#
Navigation lets you traverse links and read data from linked records using dot-separated key paths called navigation keys.
Navigation Keys#
A navigation key is a dot-separated path where each segment before the last is a key containing links, and the final segment is the key to read from the destination record.
1 | |
This means: follow the employer link, then read the name key
from the linked record.
Using navigate()#
The navigate method traverses navigation keys and returns data
from the destination records.
1 2 3 4 | |
1 2 | |
Multi-Hop Navigation#
Navigation keys can span multiple hops:
1 | |
This traverses two links: first employer, then ceo, and
finally reads name from the destination.
1 2 3 | |
Navigate Multiple Keys#
1 2 3 4 5 6 | |
Navigate from Multiple Records#
1 2 3 4 | |
Navigate with Criteria#
Navigate from all records matching a query:
1 2 3 4 | |
Historical Navigation#
1 2 3 4 | |
Navigation Keys in Queries#
Navigation keys can be used directly in CCL conditions to filter records based on data in linked records:
1 | |
1 2 3 | |
This finds all records whose linked employer record has a
name of "Cinchapi". Navigation keys work with all CCL
operators:
1 2 3 | |
Transitive Navigation#
When a field contains self-referential links — for example,
a children key whose links point to more records that also have
children — the depth of the graph is data-dependent. You
can follow those links recursively by appending a * suffix to
any stop in a navigation path.
1 2 3 | |
The * tells the server to expand that stop with a
breadth-first search: start from the links at the current stop,
follow them to their destinations, and if any destination record
also has outgoing links on the same field, follow those too,
until no new records are discovered. The entire traversal runs
server-side in a single RPC.
Cycles and Termination#
Transitive traversal automatically deduplicates records as the BFS frontier expands, so cyclic graphs (e.g., a record that eventually links back to an ancestor) terminate cleanly without infinite loops. The result includes each reachable record at most once.
Examples#
1 2 3 4 5 6 7 8 9 | |
1 2 3 4 5 | |
1 2 3 | |
Mixed Stops in the Same Key#
A navigation path can combine transitive and non-transitive
stops. Each * expands independently:
1 | |
This follows parent once (single hop), then expands the
children field transitively on the destination record, then
reads name at every descendant.
Multiple transitive stops in the same key are also supported:
1 | |
Each * expands via its own BFS; the traversals compose in
order along the path.
Supported Operations#
Transitive keys work anywhere a navigation key works:
| Operation | Transitive keys |
|---|---|
select |
✓ |
get |
✓ |
navigate |
✓ |
browse |
✓ |
find |
✓ |
Non-Link Fields#
If the * modifier is applied to a stop whose field does not
contain links (for example, a plain string field), the BFS finds
no outgoing edges to follow and the traversal terminates
immediately. The result is the same as the non-transitive
variant of the same key — transitive navigation degrades
gracefully rather than raising an error.
Tracing References#
The trace method returns all incoming links to a record —
it answers the question “which records link to this one?”
1 2 3 4 | |
1 2 | |
The result maps each key name to the set of records that contain a link to the traced record via that key.
Trace Multiple Records#
1 2 3 | |
Historical Trace#
1 2 3 4 | |
Consolidating Records#
The consolidate method atomically merges data from one or more
source records into a target record. Every field from each
source is added to the target, the sources are cleared, and
every incoming link in the database that referenced a source is
rewritten to point at the target. The operation is atomic
— either every source is fully consolidated and every
incoming link is rewritten, or nothing changes.
1 2 3 | |
1 2 | |
Consolidation is useful when resolving duplicate records or normalizing references across a graph. Because it rewrites inbound links in place, callers that held a link to a source record continue to work — their link now resolves to the consolidated target.
Traversal Optimization#
Concourse automatically selects the most efficient traversal strategy for navigation queries. Depending on the shape of the data, it may use:
-
Forward traversal: Start from the source records and follow links forward to find destination data. This is more efficient when there are fewer source records than destination records.
-
Reverse traversal: Start from potential destination records and trace links backward to find matching sources. This is more efficient when there are fewer destination records than source records.
The optimizer chooses the strategy automatically based on data characteristics. No manual tuning is required.
For transitive keys, the same optimizer considers both strategies but biases toward reverse traversal when the first stop in the path is transitive, since a forward-expansion starting point would need to enumerate an unbounded subgraph before doing any filtering.