Which Rules Must Every Asset Write Preserve?
Separate key presence, uniqueness and lookup performance, then audit existing data before installing graph constraints.
12 sections · 4 questions · 1 coding challenge
The arrow keys move between sections too.
Flexible Records Still Needed Shared Invariants
BOTIE
The purpose here is narrower than making every node identical. All Asset nodes need an unambiguous application identity, while different kinds of equipment can still have different optional properties.
Sources for this history
The Second P7 Broke the Meaning of Every Match
A query that used to locate one P7 now finds two nodes. Some relationships point to one copy and some to the other. Botie cannot repair that ambiguity by choosing whichever match appears first.
The application needs a durable identity rule enforced at the write boundary. An index can help find an asset, but a constraint is what rejects a forbidden duplicate. Those responsibilities are related without being interchangeable.
Invented maintenance records. Python exercises and workshop components expose the mechanism locally. Source-linked Cypher or SPARQL examples require the stated external database setup.
Step 1 of 1
Duplicate node identities split the maintenance history
The display shows two different stored nodes with the same forbidden application key.
Nodes and properties (4)
- P7 copy A · Asset key P7
- I1 · Inspection
- P7 copy B · Asset key P7
- I2 · Inspection
- P7 copy A to I1: HAS_INSPECTION
- P7 copy B to I2: HAS_INSPECTION
Audit identity before installing the constraint
Repeated usable IDs and missing usable IDs are independent violations. Keeping both results prevents uniqueness from being mistaken for complete key validity.
Audit identity before installing the constraint
Some imported nodes repeat an ID and others have no usable one.
BOTIE
Result for these records
[
[
"P7"
],
2
]Follow the operations
1. Unvalidated imported node records
[ { "id": "P7", "kind": "Asset" }, { "id": "P7", "kind": "Asset" }, { "kind": "Asset" }, { "id": "", "kind": "Asset" }, { "id": "P8", "kind": "Asset" } ]2. Find repeated known IDs
- 0P7
3. Count missing or invalid IDs
2
4. Collect two results
[ [ "P7" ], 2 ]5. Result
[ [ "P7" ], 2 ]
These components operate on the supplied records in your browser. They do not run a graph database or interpret Cypher.
1. Separate presence from uniqueness
A uniqueness rule prevents repeated known key values. It does not necessarily require every node to carry that key. A node with no application ID can remain difficult to address even when all present IDs are unique.
For this import audit, a valid ID is a nonempty string. Count missing, blank or nonstring IDs separately from duplicate known IDs. Production databases may offer key, existence and type constraints with edition-specific availability.
Passing the duplicate check does not establish that every record has a usable identity.
2. Audit the existing records first
Creating a constraint over conflicting data can fail. Inspect the duplicate groups and missing keys, decide which nodes are genuine duplicates, and preserve their attached relationships while repairing them.
Do not delete a duplicate-looking node simply because its ID repeats. Its relationships may contain the only copy of an inspection association. A migration needs a reviewed reconciliation rule and a recovery path.
The exercise reports problems without changing the records.
Count missing key values separately
These rows have no duplicate valid ID, but one lacks any ID.
nodes=[{'id':'P7'},{'name':'Unregistered pump'}]
print(sum(not isinstance(n.get('id'),str) or not n['id'] for n in nodes))1An empty duplicate list would not make this import valid.
3. Install the identity constraint deliberately
The first statement below creates uniqueness for Asset.id. Neo4j backs property uniqueness constraints with an index, so it can also support the identity lookup. This does not turn every other property into a constrained field.
Property existence and type constraints, and node-key constraints, have edition/version requirements. Validate required fields at ingestion and use the database-supported rule set for the deployment; do not advertise a uniqueness-only rule as mandatory-key enforcement.
A query plan and a data invariant answer different questions.
Run in your own environment
Create and inspect an asset identity constraint
Run schema changes with an authorised administrative role in a disposable test database.
Use an empty Neo4j test database or first repair duplicate Asset.id values.
This uniqueness constraint does not require id on every Asset. For deployments that support it, CREATE CONSTRAINT asset_id_required IF NOT EXISTS FOR (a:Asset) REQUIRE a.id IS NOT NULL adds an existence rule; check the edition requirement before running it.
CREATE CONSTRAINT asset_id_unique IF NOT EXISTS
FOR (a:Asset) REQUIRE a.id IS UNIQUE;
SHOW CONSTRAINTS;The installed constraint rejects duplicate known IDs. Missingness remains a separate obligation.
Official documentation. Documentation checked .
Check yourself
Questions on Parts 1 to 3
Question 1 of 2
What should the audit report?
Use the information below.
The IDs are P7, P7, missing, empty string and P8. A usable ID is a nonempty string.4. Use indexes for the predicates that actually locate nodes
An index on a label/property combination can help a selective starting lookup. It does not automatically speed every relationship traversal or every expression applied to that property.
Inspect the plan for the actual query and representative parameters. Extra indexes consume storage and add write work, so create them around measured access patterns rather than every possible field.
Index presence is not proof that a particular query uses it.
5. Keep application rules alongside database rules
A uniqueness constraint does not verify that an asset belongs to the caller’s tenant or that a proposed dependency is physically sensible. The database may enforce some structural rules while application policy checks the rest.
Document which boundary owns each rule and test writes through every supported path. A bulk loader that bypasses an application check can otherwise reintroduce the same problem.
The workshop’s independent duplicate and missing-ID branches are an audit, not an installed database constraint.
Check yourself
Questions on Parts 1 to 5
Question 1 of 2
What should establish whether the index helps?
Use the information below.
An index exists on Asset.id but a query filters on an unrelated expression.Try it with Botie
Build with Botie
Write and run Python