---
title: nexyron.temporal_history
url: https://nexyron.tech/docs/cypher/procedures/temporal-and-streaming/nexyron-temporal-history
description: Read the hidden timestamped history for one declared temporal property on one known subject node.
---

# nexyron.temporal_history

## Generic Description

Read the hidden timestamped history for one declared temporal property on one known subject node.

Simple example:

```cypher
MATCH (u:User {id: 'user-17'})
CALL nexyron.temporal_history(element_id(u), 'weight', null, null)
YIELD node_id, property, ts, value
RETURN node_id, property, ts, value
ORDER BY ts
```

Temporal and streaming procedures inspect registered temporal history, rollups, time ranges, and global event timelines.

## Consumer-Level Explanation

Use `nexyron.temporal_history` when you already know the subject node and property name and want the raw recorded values behind that property.

This is the direct procedure-level read path for temporal properties. It returns the actual history records, not a rollup and not a graph-visible event family.

Temporal histories do not float independently from graph entities. The subject node must exist when history is appended, and deleting that node removes its hidden temporal history and timeline contributions.

The first argument is a node key. It accepts either the internal integer `id(node)` or the public node element id string from `element_id(node)`, for example `n:180098582026649600`. Feature contracts whose abstraction `subject_id` is already a node element id can pass `$subject_id` directly; contracts backed by business keys should first match the owner node and pass `element_id(owner)` or `id(owner)`.

The optional time-window arguments accept canonical `i64` epoch-millisecond integers. `timestamp()`, `currenttimestamp()`, `current_timestamp()`, `now()`, and `datetime(...)` all return that same format, and plus/minus integer arithmetic shifts by milliseconds.

When the surrounding query uses `ASOF`, `nexyron.temporal_history` is capped by that point-in-time context. Passing `null` as `to` means "up to the ASOF timestamp", and passing a later explicit `to` is treated as `min(to, ASOF)`. The procedure still returns raw timestamped rows; use normal property access such as `u.weight` or `u.profile_state` under `ASOF` when you only need the latest scalar or object value at that point.

## Conceptual Explanation

Temporal properties keep a hidden append-only history under an ordinary node property such as `User.weight`, `Device.battery_pct`, or `Account.status`.

`nexyron.temporal_history` reads that hidden history directly:

-   one subject node
-   one property
-   optional time window

That makes it the right tool when you need the full recorded sequence and plan to run downstream sequence analytics such as `lag`, `lead`, `diff`, `changes`, or custom list processing.

For object-valued temporal properties, the `value` column contains the recorded object for each returned row. It does not automatically unwrap one field; project fields from `value` only after confirming the declared `index_paths` or the actual object shape.

## More Detailed Explanation

In practical queries, start by deciding the row grain you want after the call: one row per node, one row per path, one row per registry object, one row per artifact, or one row per summary. Then keep that grain explicit with `YIELD` and named projections. That is the difference between a useful planner-facing example and a vague call that downstream tooling cannot safely compose. For contract-driven procedures, the executable examples on these pages intentionally inspect procedure metadata unless the required named artifacts are created in the same example.

## Advanced Example

```cypher
MATCH (u:User {id: 'user-17'})
WITH element_id(u) AS user_id
CALL nexyron.temporal_history(user_id, 'workplace', currenttimestamp() - 30 * 24 * 60 * 60 * 1000, null)
YIELD ts, value
RETURN ts, value
ORDER BY ts
```

Resolve the owning node from a temporal row:

```cypher
MATCH (u:User {id: 'user-17'})
WITH element_id(u) AS user_id
CALL nexyron.temporal_history(user_id, 'workplace', null, null)
YIELD node_id, ts, value
WITH node_id AS temporal_owner_key, ts, value
MATCH (owner)
WHERE id(owner) = temporal_owner_key
RETURN owner, id(owner) AS owner_id, ts, value
ORDER BY ts
```

## Real Use Cases

-   Read one person’s employment-history values over time without materializing separate visible event nodes.
-   Inspect the raw battery percentage history for one device before choosing a bucket width for rollups.
-   Pull the full history of one object-valued temporal property before projecting selected subfields in application code.

## Real Limitations And Tradeoffs

-   This procedure is point-targeted. It is not the right surface when you need history for many subjects at once.
-   It returns raw records, so large subject histories can still be expensive compared with rollup reads.
-   It assumes the property was declared temporal. Ordinary non-temporal properties have no hidden history here.
-   Under `ASOF`, the procedure's upper bound is capped to the ASOF timestamp; it will not return future temporal rows from after that point.
-   If the owner node has been deleted, its hidden temporal-property history is deleted with it. Model graph-visible audit events as event nodes if they must survive subject deletion.
-   The temporal row's `node_id` is the owner node ID for the property history. It is not inferred from the `value` payload. For grouped business questions, start from the graph path to the owner nodes first, then read their temporal history.
