Capturing key properties

This feature has been released as a public beta in AuraDB Enterprise October Release and Neo4j Enterprise Edition 5.13 and breaking changes are likely to be introduced before it is made generally available (GA).

Neo4j internally identifies nodes and relationships by their elementId. Although these internal identifiers are always part of the generated change events, they are not safe to track data out of the scope of a single transaction. You should thus define logical/business keys to your graph entities in the form of node key constraints and relationships key constraints. Properties with node and relationship key constraints are always included in change events as top-level objects.

Note that node key constraints are equivalent to having both unique node property and node property existence constraints defined on the same properties. Similarly, relationship key constraint are equivalent to having both unique relationship property and relationship property existence constraints defined on the same properties.
For Change Data Capture, it doesn’t matter whether the constraints were created in one way or the other.

If key constraints are defined on graph entities, all of the participating property values are captured as event.keys field on node changes and event.key field on relationship changes. Furthermore, a relationship change also includes the corresponding participating key property values for the relationship’s start and end nodes.

If the or relationship key constraints are added after a change event is captured, the previously captured change events are not updated with key information retroactively. The key properties are captured from the point the corresponding constraints are created.

Node keys

Assume that we have the following constraints for Person and Employee labels.

Node key constraint for Person label
CREATE CONSTRAINT person_key IF NOT EXISTS FOR (n:Person) REQUIRE (n.firstName, n.lastName) IS NODE KEY
Node key constraint for Employee label
CREATE CONSTRAINT employee_key IF NOT EXISTS FOR (n:Employee) REQUIRE (n.id) IS NODE KEY

Whenever a change happens on a node with Person label with firstName and lastName properties set as john and doe respectively, the change event includes the following key information.

{
    //...
    "event": {
        "keys": {
            "Person": {
                "firstName": "john",
                "lastName": "doe"
            }
        }
    }
    //...
}

Likewise, whenever a change happens on a node with Employee label with id property set as 1001, the change event includes the following key information.

{
    //...
    "event": {
        "keys": {
            "Employee": {
                "id": 1001
            }
        }
    }
    //...
}

If, on the other hand, the changed node has both Person and Employee labels with firstName, lastName and id properties set as john, doe and 1001 respectively, the change event includes the following key information.

{
    //...
    "event": {
        "keys": {
            "Person": {
                "firstName": "john",
                "lastName": "doe"
            },
            "Employee": {
                "id": 1001
            }
        }
    }
    //...
}

For a full description of change record schema, see Change event schema.

Although the preferred way of specifying node key properties is creating a node key constraint, the same can be achieved using both unique node property and node property existence constraints on the same set of properties.

CREATE CONSTRAINT person_firstName_exists FOR (n:Person) REQUIRE n.firstName IS NOT NULL;
CREATE CONSTRAINT person_lastName_exists FOR (n:Person) REQUIRE n.lastName IS NOT NULL;
CREATE CONSTRAINT person_unique FOR (n:Person) REQUIRE (n.firstName, n.lastName) IS UNIQUE;

For details about constraints and syntax of related commands, see Cypher Manual → Constraints.

Relationship keys

Assume that you have the following constraints for MARRIED_TO relationship type.

Relationship key for MARRIED_TO type
CREATE CONSTRAINT married_to_key FOR ()-[r:MARRIED_TO]-() REQUIRE (r.registerId) IS RELATIONSHIP KEY

Whenever a change happens on a relationship of type MARRIED_TO with registerId property set as 1125, the change event includes the following key information.

{
    //...
    "event": {
        "key": {
            "registerId": 1125
        }
    }
    //...
}

If the relationship’s start and end nodes correspond to nodes with node key constraint, those property values are also included in the change event.

{
    //...
    "event": {
        "start": {
            "elementId": "<element-id>",
            "labels": ["Person"],
            "keys": {
                "Person": {
                    "firstName": "john",
                    "lastName": "doe"
                }
            }
        },
        "end": {
            "elementId": "<element-id>",
            "labels": ["Person"],
            "keys": {
                "Person": {
                    "firstName": "mary",
                    "lastName": "doe"
                }
            }
        },
        "key": {
            "registerId": 1125
        }
    }
    //...
}

For a full description of change record schema, see Change event schema.

Although the preferred way of specifying relationship key properties is creating relationship key constraint, the same can be achieved using both unique relationship property and relationship property existence constraints on the same set of properties.

CREATE CONSTRAINT married_to_registerId_exists FOR ()-[r:MARRIED_TO]-() REQUIRE (r.registerId) IS NOT NULL;
CREATE CONSTRAINT married_to_registerId_unique FOR ()-[r:MARRIED_TO]-() REQUIRE (r.registerId) IS UNIQUE;

For details about constraints and syntax of related commands, see Cypher Manual → Constraints.