Chapter 09 · Constraints and Indexes: Range, Text, Point, Token, Full-Text, and Schema Enforcement
Uniqueness, Key, Property Existence, Property Type, and Other Constraints as Executable Model Contracts
Turn AtlasMart integrity assumptions into explicit, edition-aware database contracts.
Learning outcomes
AtlasMart has reached the point where “the application usually writes valid data” is no longer an integrity strategy. Product identifiers arrive from imports and APIs, order-line relationships are retried, and different services can mutate the graph. The first job is to decide which rules must be executable database contracts and which remain application-level validation.
Distinguish labels/types used for classification from constraints used for integrity.
Explain uniqueness, existence, property-type and key constraints precisely.
State which constraint families are available in Community versus Enterprise.
Observe constraint state and backing indexes with SHOW CONSTRAINTS/SHOW INDEXES.
Prove a violation safely and separate database guarantees from remaining business invariants.
The mandatory lab continues Neo4j Community
2026.07.1, database neo4j, explicit
CYPHER 25 for version-sensitive examples,
authentication enabled, no mandatory APOC/GDS plugin, and the
AtlasMart identifiers/model established in Chapters 01–08.
Neo4j 5.26.30 remains the LTS comparison line.
Community currently supports node and relationship
property-uniqueness constraints. Property-existence,
property-type and key constraints—and Cypher 25 graph
types—are Enterprise-only; Enterprise examples in this chapter
are optional and are never presented as Community output.
This generation environment does not run Neo4j or Docker.
Commands were checked against current official documentation
but were not executed here. Expected plans, counts, index
states and scores are therefore described by invariant rather
than fabricated as captured output. All disposable data uses
labTag='ch09'; all disposable schema objects are
named ch09_*. Never drop an index/constraint
merely because its name looks similar to a lab object—verify
SHOW INDEXES/SHOW CONSTRAINTS first.
1. Classification is not enforcement
A label such as :Product tells Cypher which class
of node a pattern is discussing. It does not require
productId to exist, be unique, or have a particular
type. The same is true for relationship type
:CONTAINS. Integrity begins only when a rule is
enforced by a constraint or by an application transaction that
tests and writes atomically.
| Contract | Guarantee | Community 2026.07.1 | Enterprise 2026.07.1 | Index-backed |
|---|---|---|---|---|
| Property uniqueness | Present values/combinations must be unique | Yes · nodes + relationships | Yes | Yes · range index |
| Property existence | Required property cannot be missing | No | Yes | No |
| Property type | Property must match declared type | No | Yes | No |
| Key | Properties must exist and their combination must be unique | No | Yes · nodes + relationships | Yes · range index |
| Graph types | Holistic element/schema contract | No | Yes · Cypher 25 preview | Depends on contained constraints |
2. Uniqueness is not existence
A uniqueness constraint only evaluates entities that contain all
constrained properties. Therefore
REQUIRE p.productId IS UNIQUE prevents two products
from sharing the same present ID, but it does not require every
:Product to have productId. That
distinction is central to Community deployments: if product IDs
are mandatory, Community needs an explicit validation gate in
addition to the uniqueness constraint.
CYPHER 25CREATE CONSTRAINT product_id IF NOT EXISTSFOR (p:Product) REQUIRE p.productId IS UNIQUE;CREATE CONSTRAINT category_id IF NOT EXISTSFOR (c:Category) REQUIRE c.categoryId IS UNIQUE;CREATE CONSTRAINT order_id IF NOT EXISTSFOR (o:Order) REQUIRE o.orderId IS UNIQUE;CREATE CONSTRAINT ch09_contains_line_id_unique IF NOT EXISTSFOR ()-[r:CONTAINS]-() REQUIRE r.lineId IS UNIQUE;
CYPHER 25SHOW CONSTRAINTSYIELD name,type,entityType,labelsOrTypes,properties,ownedIndexRETURN name,type,entityType,labelsOrTypes,properties,ownedIndexORDER BY name;
3. Enterprise-only contracts are stronger, not interchangeable
If AtlasMart later licenses Enterprise, a key constraint can encode both existence and uniqueness in one contract, while existence/type constraints can independently require a property and its type. These commands are shown for semantics only; do not run them in the mandatory Community lab.
CYPHER 25// Enterprise only — do not run in the Community lab.CREATE CONSTRAINT product_key IF NOT EXISTSFOR (p:Product) REQUIRE p.productId IS NODE KEY;CREATE CONSTRAINT product_name_required IF NOT EXISTSFOR (p:Product) REQUIRE p.name IS NOT NULL;CREATE CONSTRAINT product_price_type IF NOT EXISTSFOR (p:Product) REQUIRE p.price IS :: FLOAT;
4. Deliberately wrong: “the :Product label makes productId mandatory”
Create a disposable product without a business key after the uniqueness constraint exists. If the write succeeds, the evidence proves exactly why uniqueness does not imply existence.
CYPHER 25CREATE (:Product {name:'Missing-ID Probe',labTag:'ch09'});MATCH (p:Product) WHERE p.labTag='ch09' AND p.productId IS NULLRETURN count(p) AS missingProductIds,collect(p.name) AS examples;
The Community repair is to reject/quarantine rows with missing IDs before mutation and to keep the uniqueness constraint for concurrent duplicate protection. The Enterprise repair can instead promote the requirement into a key or existence contract.
5. Constraint creation is a migration event
Adding a constraint scans existing data and is atomic. It can fail because existing rows violate the rule, and uniqueness/key creation also creates a backing range index. Measure build impact on production-like data, schedule the change, and understand that dropping an index-backed constraint also drops its backing index.
CYPHER 25SHOW INDEXESYIELD name,type,state,entityType,labelsOrTypes,properties,owningConstraintWHERE owningConstraint IS NOT NULLRETURN name,type,state,labelsOrTypes,properties,owningConstraintORDER BY owningConstraint;
Hands-on integrity lab
CYPHER 25MERGE (c1:Category {categoryId:'CAT-9001'}) SET c1.name='Field Electronics',c1.labTag='ch09'MERGE (c2:Category {categoryId:'CAT-9002'}) SET c2.name='Power',c2.labTag='ch09'MERGE (p1:Product {productId:'P-9001'}) SET p1.name='Trail Camera Pro',p1.description='weatherproof wildlife camera with night vision',p1.categoryCode='CAM',p1.price=189.0,p1.location=point({latitude:40.7128,longitude:-74.0060}),p1.labTag='ch09'MERGE (p2:Product {productId:'P-9002'}) SET p2.name='Trail Camera Mini',p2.description='compact wildlife camera',p2.categoryCode='CAM',p2.price=99.0,p2.location=point({latitude:40.7138,longitude:-74.0040}),p2.labTag='ch09'MERGE (p3:Product {productId:'P-9003'}) SET p3.name='Field Battery',p3.description='high capacity outdoor battery pack',p3.categoryCode='PWR',p3.price=49.0,p3.location=point({latitude:40.7100,longitude:-74.0100}),p3.labTag='ch09'MERGE (p1)-[:IN_CATEGORY]->(c1)MERGE (p2)-[:IN_CATEGORY]->(c1)MERGE (p3)-[:IN_CATEGORY]->(c2)MERGE (o:Order {orderId:'O-9001'}) SET o.labTag='ch09',o.status='PAID'MERGE (o)-[r1:CONTAINS]->(p1) SET r1.lineId='L-9001',r1.quantity=1,r1.unitPrice=189.0,r1.labTag='ch09'MERGE (o)-[r2:CONTAINS]->(p3) SET r2.lineId='L-9002',r2.quantity=2,r2.unitPrice=49.0,r2.labTag='ch09';
CYPHER 25// Expect this statement to fail because P-9001 already exists.CREATE (:Product {productId:'P-9001',name:'Duplicate Probe',labTag:'ch09'});
CYPHER 25MATCH (p:Product)WHERE p.labTag='ch09' AND p.productId IS NULLRETURN count(p) AS invalidProducts;// After proving the boundary, remove only the deliberate missing-ID probe.MATCH (p:Product {name:'Missing-ID Probe',labTag:'ch09'}) DETACH DELETE p;
Check your understanding
- Why can a uniqueness-constrained Product still lack productId?
- Which current constraint families are Community-safe in this lesson?
- What additional guarantee does a key constraint provide?
- Why does creating a uniqueness constraint affect index inventory?
- Does a constraint encode every AtlasMart business rule?
Review the answers
1. Uniqueness constrains present values; it does not imply property existence.
2. Node and relationship property-uniqueness constraints.
3. The constrained property set must exist and the value combination must be unique.
4. Neo4j creates a backing range index owned by that constraint.
5. No. Cross-entity cardinality, temporal overlap, workflow state and many other rules still need transactional/application validation.
Production judgment and next step
Constraints are correctness contracts with migration and write-path cost; use them for invariants the database can express, not as decorative schema. Keep validation queries for rules Community cannot encode and for graph-wide/business invariants that no current individual constraint expresses. Next, the chapter separates those integrity contracts from indexes whose primary purpose is query access.
Summary and next step
Uniqueness, Key, Property Existence, Property Type, and Other Constraints as Executable Model Contracts is useful only when its assumptions and observed evidence stay attached to the decision. The examples above establish a reproducible mechanism and boundary; they do not turn one lab result into a universal production rule.
Next, continue to Range, Text, Point, and Token Lookup Indexes: Supported Predicates and Workload Fit. Carry forward the verified assumptions, fixture state, version/edition boundaries, and measurements from this lesson instead of treating the next topic as an isolated recipe.
Authoritative references
- Current Neo4j versions — Release/LTS snapshot used for this chapter.
- Constraints — Current constraint types and edition boundaries.
- Create constraints — Current uniqueness, existence, type and key syntax and backing-index behavior.
- Search-performance indexes — Range, text, point and token lookup index semantics.
- Show indexes — Index lifecycle, state, population and usage evidence.
- Full-text indexes — Full-text schema, analyzers, query procedures and eventual-consistency behavior.
- Built-in index procedures — db.awaitIndex(es) and full-text refresh/analyzer procedures.
- Cypher and Neo4j editions — Current Community/Enterprise schema capability matrix.
- Show constraints — Current SHOW CONSTRAINTS evidence and Cypher 25 composability.