OriginChainDB docs
examples · graph · 9 / 17

9. components - split the graph into islands

← Graph examples

what this does

components partitions every row under a schema into connected islands. GET /v1/tenants/:t/graph/:schema/components walks rel as undirected, runs union-find over the whole node universe, and returns one entry per node carrying the id of the component it landed in. Every row comes back, including rows with no edges at all - those are components of one.

when to use it

  • "Is this one network or several?" - the first thing to establish before running any global algorithm over the graph.
  • Orphan detection. A node alone in its component has no relationships at all, which is usually either a data-quality problem or the answer you were looking for.
  • Partitioning work. Run an expensive per-island analysis on each component independently instead of on the whole graph at once.

schema requirement

The relation must be declared in the schema's [[relations]] block and must target the table it is declared on. See schemas/reference#relations.

the request

rel names the relation. The optional include_rows=true switch also echoes each row's full body alongside its component id; leave it off unless you need the columns, because the default response carries only what the algorithm actually computed.

GET /v1/tenants/:t/graph/:schema/components?rel=...
curl -G "https://$OC_HOST/v1/tenants/$OC_TENANT/graph/social.users/components" \
  --data-urlencode "rel=follows" \
  -H "Authorization: Bearer $OC_TOKEN"

what you get back

[
  { "pk": ["alice"],   "_component": "[\"alice\"]" },
  { "pk": ["bob"],     "_component": "[\"alice\"]" },
  { "pk": ["carol"],   "_component": "[\"alice\"]" },
  { "pk": ["heidi"],   "_component": "[\"heidi\"]" },
  { "pk": ["ivan"],    "_component": "[\"heidi\"]" },
  { "pk": ["judy"],    "_component": "[\"heidi\"]" },
  { "pk": ["mallory"], "_component": "[\"mallory\"]" }
]

One entry per node. pk is the node's primary-key array. _component is the canonical JSON encoding of the component root's primary key, which makes it a string containing a JSON array, not an array. Treat it as an opaque grouping key: nodes that share it are in the same island. With include_rows=true each entry additionally carries the row's own columns, next to the same _component field.

how it works

  • Union-find over the schema's whole node universe, with every rel edge treated as undirected.
  • Each row is emitted exactly once whether or not it has edges, so the number of distinct _component values is the number of islands.
  • The compact {pk, _component} shape is the default because the algorithm's entire answer is one id per node. Echoing row bodies made the response grow with row width without adding information.
  • include_rows=true restores the earlier verbatim-row shape for callers that depended on it. The partitioning is identical either way - only the payload changes.

common mistakes

  • Treating _component as a key you can look up. It is a canonical-JSON string, not a bare primary key and not an integer. Group on it; do not try to resolve it back to a row.
  • Reaching for include_rows=true by habit. It multiplies the response by your row width. Get the partition first, then fetch only the rows you actually want by primary key.
  • Expecting isolated rows to be absent. A row with no edges is a component of one and is present in the response.