Use CDC to query changes (procedures)

Once CDC is enabled, there are a number of Cypher procedures that you may use to query changes.

CDC works with change identifiers, which are essentially pointers to specific transactions. The CDC procedures allow you to retrieve specific change identifiers or to query for changes that affected the database after a given change identifier.

Change identifiers are local to the database they are generated for, and cannot be used to query changes on another database. Keep this in mind when restoring a database from a backup, since the restored database is practically a new database. See restore from backup for details.

Retrieve the earliest change identifier

The procedure db.cdc.earliest returns the change identifier for the earliest available change.

Example 1. Query earliest change identifier
Query
CALL db.cdc.earliest()
Table 1. Result
id

"A3V16ZaLlUmnipHLFkWrlA0AAAAAAAAABQAAAAAAAAAA"

Retrieve the current change identifier

The procedure db.cdc.current returns the change identifier for the last committed transaction.

Note that the returned identifier is exclusive: it does not include the changes that happened in the transaction it points to.

Example 2. Query current change identifier
Query
CALL db.cdc.current()
Table 2. Result
id

"A3V16ZaLlUmnipHLFkWrlA0AAAAAAAAABQAAAAAAAAAA"

Query changes

The procedure db.cdc.query returns the changes that happened to the database after the given change identifier.

db.cdc.query(
    from =  :: STRING?, (1)
    selectors = [] :: LIST? OF MAP? (2)
) :: (
    id :: STRING?, (3)
    txId :: INTEGER?, (4)
    seq :: INTEGER?, (5)
    metadata :: MAP?, (6)
    event :: MAP? (7)
)
1 The change identifier to query changes from, either captured from an earlier call to db.cdc.query or from one of db.cdc.current or db.cdc.earliest. The default value is "" (empty string) which is replaced with db.cdc.current implicitly. This value is treated as exclusive, so the results of the query do not include the changes that happened on the transaction corresponding to this change identifier.
2 An optional list of selectors to filter out changes. The default is an empty list, which means all changes are returned, without any filtering.
3 The unique change identifier associated with each change record. Each of these can be used for further db.cdc.query calls.
4 A number identifying which transaction the change happened in, unique in combination with seq. Transaction identifiers are not continuous (some transactions, such as system and schema commands, are not recorded in change data capture and cause gaps in the transaction identifiers).
5 A number used for ordering changes that happened in the same transaction. Note that the order of changes observed in the output does not necessarily correspond to the order in which changes were applied during the transaction.
6 A map of values containing transaction metadata. This is the same for all of the changes in a single transaction. For a detailed description of the metadata fields, see Format of change events.
7 The retrieved changes on the affected entity. For a detailed description of the change event, see Format of change events.
Example 3. Query for changes after creation of a :Person node
Query
CALL db.cdc.query("A3V16ZaLlUmnipHLFkWrlA0AAAAAAAAABAAAAAAAAAAA")
Table 3. Result
id txId seq metadata event

"A3V16ZaLlUmnipHLFkWrlA0AAAAAAAAABQAAAAAAAAAA"

4

0

{
  "txStartTime": "2024-04-03T06:28:19.630000000Z",
  "databaseName": "neo4j",
  "executingUser": "neo4j",
  "authenticatedUser": "neo4j",
  "connectionServer": "172.17.0.2:7687",
  "connectionType": "bolt",
  "serverId": "20668765",
  "captureMode": "FULL",
  "connectionClient": "172.17.0.1:41888",
  "txCommitTime": "2024-04-03T06:28:19.651000000Z",
  "txMetadata": {
    "app": "neo4j-browser_v5.15.0",
    "type": "user-direct"
  }
}
{
  "elementId": "4:68262997-88e3-4518-83ec-d944674609f4:8",
  "operation": "c",
  "keys": {

  },
  "labels": [
    "Person"
  ],
  "state": {
    "after": {
      "labels": [
        "Person"
      ],
      "properties": {
        "name": "Stefano"
      }
    },
    "before": null
  },
  "eventType": "n"
}

Retrieve the earliest change event

The procedure db.cdc.earliest returns the change identifier for the earliest available change, but not the associated change event information. To retrieve the earliest change event, you can feed the earliest change ID into db.cdc.query and limit the result to one. Change events are already sorted chronologically so no sorting is needed.

CALL db.cdc.earliest() YIELD id AS earliestId
CALL db.cdc.query(earliestId) YIELD event, metadata
RETURN event, metadata LIMIT 1

Retrieve the most recent change event

To retrieve the most recent change event, you can feed the earliest change ID into db.cdc.query, reverse-sort them, and limit the result to one.

CALL db.cdc.earliest() YIELD id AS earliestId
CALL db.cdc.query(earliestId) YIELD event, metadata
RETURN event, metadata ORDER BY metadata.txCommitTime DESC LIMIT 1
This query can be very slow, as it needs to scan through all change events.

A minimal working example

The easiest way to see CDC in action is by retrieving the current change identifier, creating a new node in the database, and then querying for changes using the previous change identifier. The operations must happen in three separate transactions.

Transaction 1 — Retrieve current change ID
CALL db.cdc.current() YIELD id AS currentId
// currentId = 'BaQswf9NV0b7qicwDdh7vfwAAAAAAAAD83__________AAABjzfm4bM'
Transaction 2 — Create new Person node
CREATE (:Person:Hero {name: 'Batman', color: 'black'})
Transaction 3 — Retrieve change event for Person node creation
WITH 'BaQswf9NV0b7qicwDdh7vfwAAAAAAAAD83__________AAABjzfm4bM=' AS previousId
CALL db.cdc.query(previousId) YIELD event, metadata RETURN event, metadata
Table 4. Result
event metadata
{
  "elementId": "4:a42cc1ff-4d57-46fb-aa27-300dd87bbdfc:55135",
  "keys": {}, "state": {
    "before": NULL,
    "after": {
      "properties": {
        "name": "Batman",
        "color": "black"
      },
      "labels": ["Person", "Hero"]
    }
  },
  "eventType": "n",
  "operation": "c",
  "labels": ["Person", "Hero"]
}
{
  "txMetadata": {
    "app": "neo4j-browser_v5.15.0",
    "type": "user-direct"
  },
  "executingUser": "neo4j",
  "databaseName": "cdc",
  "connectionClient": "127.0.0.1:48008",
  "authenticatedUser": "neo4j",
  "captureMode": "DIFF",
  "connectionServer": "127.0.0.1:7687",
  "connectionType": "bolt",
  "serverId": "20668765",
  "txStartTime": 2024-05-02T06:13:08.521Z,
  "txCommitTime": 2024-05-02T06:13:08.551Z
}