UltipaDocs
Products
Solutions
Resources
Company
Start Free Trial
UltipaDocs
Start Free Trial
  • Introduction
  • GQL vs Other Languages
    • Overview
    • Node and Edge Patterns
    • Path Patterns
    • Quantified Paths
    • Questioned Paths
    • Shortest Paths
    • Cheapest Paths
    • K-Hop Traversal
    • Graph Patterns
    • Overview
    • Open Graphs
    • Closed Graphs
    • Graph Types
    • Constraints
    • Projections
    • Storage Maintenance
    • Node and Edge IDs
    • INSERT
    • INSERT OVERWRITE
    • UPSERT
    • MERGE
    • SET
    • REMOVE
    • DELETE
    • FOREACH
    • LOAD CSV
    • Query Composition
    • Result Table and Visualization
    • MATCH
    • OPTIONAL MATCH
    • FILTER
    • LET
    • FOR
    • ORDER BY
    • LIMIT
    • SKIP
    • CALL
    • RETURN
    • Composite Query
    • NEXT
    • All Functions
    • Element Functions
    • Path Functions
    • Aggregate Functions
    • Mathematical Functions
    • Trigonometric Functions
    • String Functions
    • List Functions
    • Datetime Functions
    • Spatial Functions
    • Null Functions
    • Utility Functions
    • Type Conversion Functions
    • Table Functions
  • Operators
  • Predicates
    • Overview
    • CASE
    • LET Value Expression
    • Value Query Expression
    • Count Query Expression
    • List Expressions
    • Current Values
    • Index
    • Full-text Index
    • Vector Index
  • Transactions
  • Triggers
  • Query Management
  • Execution Plan
    • Variables
    • Values and Types
    • Comments
    • Reserved Words
    • Naming Conventions
    • Syntactic Notation
  • GQL Conformance
  1. Docs
  2. /
  3. ISO GQL
  4. /
  5. Graph Management

Constraints

Overview

Constraints enforce extra validation on node and edge properties in the graph. Any attempt to insert or update data that violates these rules will result in an error.

Ultipa supports the following constraint types:

Constraint TypeDescriptionComposite of Properties
NOT NULLEnsures a property never contains null values.Not supported
UNIQUEEnsures a property contains no duplicate values.Supported
KEYCombines NOT NULL and UNIQUE, marking a property as the identifying key of a node type. Available on node types only.Supported
CHECKEnsures a property satisfies a custom predicate on every row, for example CHECK (price >= 0). Declared inline only.Not supported

When a constraint type supports a composite of properties, a row violates the constraint only when all listed properties match an existing row.

Showing Constraints

Show constraints in the current graph:

GQL
SHOW CONSTRAINTS
SHOW NODE CONSTRAINTS
SHOW EDGE CONSTRAINTS

Filter by the label set a constraint targets with ON:

GQL
-- Only node constraints whose target label set is {Person}
SHOW CONSTRAINTS ON (:Person)

-- Only node constraints whose target label set is {A, B}
SHOW CONSTRAINTS ON (:A&B)

-- Only edge constraints whose target label set is {KNOWS}
SHOW CONSTRAINTS ON ()-[:KNOWS]->()

To inspect a single constraint by name:

GQL
DESCRIBE CONSTRAINT myConstraint

-- DESC is a shorthand for DESCRIBE
DESC CONSTRAINT myConstraint

Each constraint provides the following metadata:

FieldDescription
nameThe user-supplied or auto-generated name..
typenode, edge, or wildcard.
matchersA list of <labels>.<properties> descriptors, one per OR alternative the constraint targets.
  • Single property: User.email.
  • Composite tuple: Person.(firstName, lastName).
  • Multi-label key set: A&B.x.
  • Wildcard target: %.status.
  • Label disjunction (:A|B): one entry per alternative, e.g. ["User.email", "Actor.email"].
constraint_typeNOT NULL, UNIQUE, KEY, or CHECK (<predicate>).

Creating Constraints

Creating a constraint on a non-empty graph scans existing data to verify compliance, and may take time on large graphs. The creation fails if any existing row violates the constraint.

Constraints can be created two ways:

CREATE CONSTRAINT

Syntax
<create constraint statement> ::=
  "CREATE" { "CONSTRAINT" [ "IF NOT EXISTS" ] | "OR REPLACE CONSTRAINT" } [ <constraint name> ]
  "FOR" <constraint scope> "REQUIRE" <constraint requirement>

<constraint scope> ::= <node constraint scope> | <edge constraint scope>

<node constraint scope> ::= "(" <node variable declaration> <label set> ")"

<edge constraint scope> ::= "()-[" <edge variable declaration> <label set> "]->()"

<label set> ::=  
    ":" <label conjunction> [ { "|" <label conjunction> }... ]
  | ":%"

<label conjunction> ::= <label name> [ { "&" <label name> }... ]

<constraint requirement> ::= <property references> "IS" <constraint type>

<property references> ::=
    <property reference>
  | "(" <property reference> [ { "," <property reference> }... ] ")"

<property reference> ::= <node/edge variable> "." <property name>

<constraint type> ::= "NOT NULL" | "UNIQUE" | "KEY"

Details

  • The constraint name is optional. When omitted, the engine derives the name from <labels>_<properties>_<type>, e.g. User_email_not_null, Person_firstName_lastName_unique. The IF NOT EXISTS and OR REPLACE variants still require an explicit name as they identify the constraint by name.
  • A constraint scope can be:
    • Single label (:A): applies to nodes/edges with that label.
    • Conjunction (:A&B): applies to nodes/edges whose contains every scope label. {A, B} and {A, B, C} both satisfy; {A} alone does not.
    • Disjunction (:A|B): applies to nodes/edges that have any of the alternatives. A, B, or both.
    • Mixed (:A&B|C): & binds tighter than |, so this parses as (A&B) | C.
    • Wildcard (:%): applies to every node or edge in the graph.
  • The CREATE CONSTRAINT statement creates NOT NULL, UNIQUE, and KEY constraints. CHECK constraints cannot be created this way; they are declared inline only (see Inline in a Type Definition).
GQL
-- NOT NULL constraint on User nodes' name
CREATE CONSTRAINT nn_user_name FOR (n:User) REQUIRE n.name IS NOT NULL

-- UNIQUE constraint on KNOWS edges' eid
CREATE CONSTRAINT FOR ()-[e:KNOWS]->() REQUIRE e.eid IS UNIQUE

-- Composite UNIQUE constraint User nodes' firstName and lastName
CREATE CONSTRAINT FOR (n:User) REQUIRE (n.firstName, n.lastName) IS UNIQUE

-- KEY constraint on User nodes' uid
CREATE CONSTRAINT user_key FOR (n:User) REQUIRE n.uid IS KEY

-- Composite KEY constraint on Account nodes' tenantId and externalId 
CREATE CONSTRAINT account_key FOR (n:Account) REQUIRE (n.tenantId, n.externalId) IS KEY

-- Wildcard NOT NULL: every node must have a non-null createdAt
CREATE CONSTRAINT FOR (n:%) REQUIRE n.createdAt IS NOT NULL

-- Wildcard UNIQUE: every edge's eid must be unique
CREATE CONSTRAINT FOR ()-[r:%]->() REQUIRE r.eid IS UNIQUE

-- Conjunction: email is unique only on nodes that carry BOTH User and Employee labels
CREATE CONSTRAINT FOR (n:User&Employee) REQUIRE n.email IS UNIQUE

-- Disjunction: email is unique on every User node and every Actor node
CREATE CONSTRAINT FOR (n:User|Actor) REQUIRE n.email IS UNIQUE

-- Mixed: parses as (Employee&Manager) | (Contractor&Lead)
-- Enforces on nodes that are EITHER {Employee, Manager} OR {Contractor, Lead}
CREATE CONSTRAINT FOR (n:Employee&Manager|Contractor&Lead) REQUIRE n.badgeId IS UNIQUE

You can use the IF NOT EXISTS clause to prevent errors when attempting to create a constraint that already exists. It allows the statement to be safely executed.

GQL
CREATE CONSTRAINT IF NOT EXISTS KNOWS_eid_unique FOR ()-[e:KNOWS]->() REQUIRE e.eid IS UNIQUE

You can use OR REPLACE to drop an existing constraint with the same name and create a new one in its place:

GQL
CREATE OR REPLACE CONSTRAINT KNOWS_eid_unique FOR ()-[e:KNOWS]->() REQUIRE e.eid IS UNIQUE

Inline in a Type Definition

Inline declaration attaches constraint type keywords directly to a property in a node or edge type definition, alongside its data type. The constraint takes effect as soon as the type is created. Inline declarations cover NOT NULL, UNIQUE, KEY, and CHECK.

Inline declarations are limited to single-property constraints. For a composite constraint, use the CREATE CONSTRAINT statement instead.

Inline constraints get the same auto-generated name as a nameless CREATE CONSTRAINT FOR …. For example, NODE User ({uid STRING KEY}) registers a constraint named User_uid_key. A property declared NOT NULL UNIQUE registers two separate constraints: <Label>_<prop>_not_null and <Label>_<prop>_unique.

When applied to the same property, constraint type keywords can be written in either order. For example, NOT NULL UNIQUE and UNIQUE NOT NULL are equivalent.

You can declare inline constraints in any of the following:

GQL
-- In a CREATE GRAPH body
CREATE GRAPH myGraph {
  NODE User ({uid STRING KEY, name STRING NOT NULL UNIQUE, age UINT32}),
  EDGE KNOWS ()-[{createdOn TIMESTAMP NOT NULL, eid STRING}]->()
}

-- In a CREATE GRAPH TYPE body
CREATE GRAPH TYPE gType {
  NODE User ({uid STRING KEY, name STRING NOT NULL UNIQUE, age UINT32}),
  EDGE KNOWS ()-[{createdOn TIMESTAMP NOT NULL, eid STRING}]->()
}

-- In CREATE NODE (add a node type to a closed graph)
CREATE NODE User ({uid STRING KEY, name STRING NOT NULL UNIQUE, age UINT32})

-- In CREATE EDGE (add an edge type to a closed graph)
CREATE EDGE KNOWS (User)-[{createdOn TIMESTAMP NOT NULL, eid STRING}]->(User)

CHECK Constraints

A CHECK constraint attaches a custom predicate to a property, enforcing a per-row invariant. A write is accepted only when the predicate holds for the row. Unlike NOT NULL, UNIQUE, and KEY, a CHECK cannot be created through the CREATE CONSTRAINT statement; it is inline only.

Declare a CHECK alongside the property's data type:

GQL
CREATE GRAPH inventory {
  NODE Product ({
    name STRING KEY,
    price FLOAT CHECK (price >= 0),
    stock INT32 NOT NULL CHECK (stock >= 0)
  }),
  EDGE Rated ()-[{ grade INT32 CHECK (grade >= 0 AND grade <= 5) }]->()
}

The same form works in CREATE GRAPH TYPE, CREATE NODE, and CREATE EDGE.

Referencing other properties

A CHECK predicate may reference any property of the same node or edge, so cross-property invariants are supported:

GQL
CREATE NODE Product ({
  cost  FLOAT,
  price FLOAT CHECK (price > cost)
})

Evaluation semantics

A CHECK follows SQL semantics: a write is rejected only when the predicate evaluates to a definite false. It passes when the predicate is true or unknown, and a predicate is unknown whenever a property it references is absent or null. To also require that the value is present, pair CHECK with NOT NULL:

GQL
CREATE NODE Product ({ stock INT32 NOT NULL CHECK (stock >= 0) })

The predicate must be deterministic: no subqueries and no side-effecting functions.

Dropping Constraints

Drop a constraint by its name:

GQL
DROP CONSTRAINT nn_user_name

The IF EXISTS clause is used to prevent errors when attempting to delete a constraint that does not exist. It allows the statement to be safely executed.

GQL
DROP CONSTRAINT IF EXISTS nn_user_name