Skip to content

Node Property Data Types

Complete reference for all supported property value types in NornicDB


Overview

NornicDB supports a rich set of data types for node and relationship properties, following Neo4j compatibility while extending support for complex nested structures. Properties are stored as map[string]any (key-value pairs) where values can be any supported type.


Supported Data Types

1. Primitive Types

String (string)

Text values of any length.

Example:

CREATE (n:Person {
  name: "Alice Johnson",
  email: "alice@example.com",
  bio: "Software engineer passionate about graph databases"
})

Use Cases: - Names, titles, descriptions - Email addresses, URLs - Text content, comments - Identifiers, codes


Integer (int, int64)

Whole numbers (positive, negative, or zero).

Example:

CREATE (n:Person {
  age: 30,
  score: 100,
  year: 2024
})

Supported Integer Types: - int (32-bit or 64-bit, platform-dependent) - int64 (64-bit signed integer) - int32 (32-bit signed integer)

Note: JSON deserialization may convert integers to float64. NornicDB accepts whole-number floats as integers for compatibility.

Use Cases: - Ages, counts, quantities - Years, timestamps - Scores, ratings - IDs, indices


Float (float64, float32)

Floating-point numbers (decimals).

Example:

CREATE (n:Product {
  price: 29.99,
  rating: 4.5,
  weight: 1.25,
  temperature: -10.5
})

Supported Float Types: - float64 (64-bit floating point, default) - float32 (32-bit floating point)

Use Cases: - Prices, measurements - Ratings, percentages - Coordinates, distances - Scientific values


Boolean (bool)

True or false values.

Example:

CREATE (n:User {
  verified: true,
  active: false,
  premium: true
})

Use Cases: - Flags, toggles - Status indicators - Feature enablement - Binary states


Null (nil)

Missing or undefined values.

Example:

CREATE (n:Person {
  name: "Alice",
  middleName: null,  // Optional field
  email: "alice@example.com"
})

Note: null is valid for any property type. Properties with null values are stored but may be omitted in queries.


2. Temporal Types

Date/Time (time.Time)

Timestamps and dates (stored as Go time.Time).

Example:

CREATE (n:Event {
  name: "Conference 2024",
  startDate: datetime("2024-06-15T09:00:00Z"),
  endDate: datetime("2024-06-17T17:00:00Z")
})

Supported Formats: - ISO 8601: "2024-06-15T09:00:00Z" - Unix timestamp: 1704067200 - Date strings: "2024-06-15"

Use Cases: - Event dates, deadlines - Created/updated timestamps - Birth dates, anniversaries - Scheduling, calendars

Note: When stored via Go API, use time.Time directly. When stored via JSON/Cypher, dates are parsed from strings.


3. Collection Types

Arrays/Lists ([]interface{}, []string, []int, []int64, []float64)

Ordered sequences of values.

Example:

CREATE (n:Person {
  name: "Alice",
  tags: ["developer", "graph-db", "go"],
  scores: [95, 87, 92],
  prices: [29.99, 49.99, 19.99],
  mixed: ["text", 42, true, 3.14]
})

Supported Array Types: - []interface{} - Mixed types (most flexible) - []string - String arrays - []int - Integer arrays - []int64 - 64-bit integer arrays - []float64 - Float arrays

Use Cases: - Tags, categories - Lists, sequences - Coordinates, vectors - Multiple values per property

Querying Arrays:

// Check if value is in array
MATCH (n:Person)
WHERE "developer" IN n.tags
RETURN n

// Access array elements
MATCH (n:Person)
RETURN n.scores[0] AS firstScore

// Array length
MATCH (n:Person)
RETURN size(n.tags) AS tagCount


Maps/Objects (map[string]interface{})

Nested key-value structures (JSON objects).

Example:

CREATE (n:Person {
  name: "Alice",
  address: {
    street: "123 Main St",
    city: "San Francisco",
    state: "CA",
    zip: "94102"
  },
  metadata: {
    created: "2024-01-15",
    version: 1,
    active: true
  }
})

Use Cases: - Nested data structures - Configuration objects - Addresses, locations - Metadata, settings

Querying Nested Objects:

// Access nested properties
MATCH (n:Person)
RETURN n.address.city AS city

// Filter by nested property
MATCH (n:Person)
WHERE n.address.state = "CA"
RETURN n

Nested Objects: Objects can be nested to any depth:

CREATE (n:Document {
  content: {
    title: "Guide",
    sections: {
      intro: {
        text: "Welcome",
        author: "Alice"
      },
      body: {
        text: "Main content",
        author: "Bob"
      }
    }
  }
})


4. Special Types

Vector Embeddings ([]float32)

Vector embeddings for semantic search (stored in NamedEmbeddings or ChunkEmbeddings, not in properties).

Note: While vectors are []float32 internally, they are not stored as regular properties. Use NamedEmbeddings or ChunkEmbeddings struct fields instead.

Example (via Cypher):

// Create node with named embedding
CALL db.index.vector.createNodeEmbedding(
  'doc-1',
  'Document',
  'content',
  'This is the document content...'
)

Example (via Go API):

node := &storage.Node{
    ID:     storage.NodeID("doc-1"),
    Labels: []string{"Document"},
    Properties: map[string]any{
        "title": "My Document",
    },
    NamedEmbeddings: map[string][]float32{
        "content": []float32{0.1, 0.2, 0.3, ...}, // 768-dim vector
    },
}

See Vector Embeddings for details.


Type Constraints (Schema Validation)

NornicDB supports property type constraints for schema enforcement on both nodes and relationships.

Supported Constraint Types: - STRING - String values only - INTEGER - Integer values only - FLOAT - Float values only - BOOLEAN - Boolean values only - DATE - Date values only - DATETIME - DateTime values only

Node property type constraints

CREATE CONSTRAINT person_age_integer FOR (p:Person) REQUIRE p.age IS :: INTEGER

// This will fail:
CREATE (p:Person {age: "thirty"})  // Error: expected INTEGER, got string

// This will succeed:
CREATE (p:Person {age: 30})  // Valid

Relationship property type constraints

Relationship constraints use the FOR ()-[var:TYPE]-() pattern:

CREATE CONSTRAINT works_at_since_date
FOR ()-[r:WORKS_AT]-() REQUIRE r.since IS :: DATE

// This will fail:
MATCH (a:Person), (b:Company)
CREATE (a)-[:WORKS_AT {since: "not-a-date"}]->(b)  // Error: expected DATE

// This will succeed:
MATCH (a:Person), (b:Company)
CREATE (a)-[:WORKS_AT {since: date("2024-01-15")}]->(b)  // Valid

Domain/enum constraints (NornicDB extension)

Domain constraints restrict a property to a fixed set of allowed values. They work on both nodes and relationships:

// Node domain constraint
CREATE CONSTRAINT person_status_domain
FOR (n:Person) REQUIRE n.status IN ['active', 'inactive', 'suspended']

// Relationship domain constraint
CREATE CONSTRAINT works_at_role_domain
FOR ()-[r:WORKS_AT]-() REQUIRE r.role IN ['engineer', 'manager', 'director']

// This will fail:
CREATE (p:Person {status: "unknown"})  // Error: value not in allowed set

// This will succeed:
CREATE (p:Person {status: "active"})  // Valid

All constraint DDL supports IF NOT EXISTS for idempotent creation. NornicDB also provides cardinality constraints (REQUIRE MAX COUNT N) to limit edge count per node, endpoint policy constraints (REQUIRE ALLOWED / REQUIRE DISALLOWED) to restrict which label pairs may be connected by a relationship type, and block-style contract definitions with REQUIRE { ... } when you need several related checks under one named schema object.

Use Managing Constraints as the canonical guide for block contracts, creation-time validation, runtime enforcement, and SHOW CONSTRAINT CONTRACTS. See Canonical Graph Ledger for a domain walkthrough and APOC Schema Functions for programmatic schema management.


Type Conversion & Coercion

JSON Deserialization

When properties are loaded from JSON (HTTP API, Cypher via JSON), type conversions occur:

  • Integers: May be deserialized as float64 (JSON limitation). NornicDB accepts whole-number floats as integers.
  • Numbers: int, int64, float32, float64 are all supported.
  • Booleans: true/false only (not 1/0 or "true"/"false").

Go API Type Handling

When using the Go API directly, types are preserved:

// Types are preserved exactly
node := &storage.Node{
    Properties: map[string]any{
        "age":    int64(30),      // Preserved as int64
        "price":  float64(29.99), // Preserved as float64
        "active": true,            // Preserved as bool
    },
}

Cypher Type Handling

Cypher queries handle type conversion automatically:

// Cypher automatically converts literals
CREATE (n:Person {
  age: 30,        // Integer
  price: 29.99,   // Float
  active: true    // Boolean
})

Examples by Use Case

User Profile

CREATE (u:User {
  // Strings
  username: "alice",
  email: "alice@example.com",
  bio: "Software engineer",

  // Numbers
  age: 30,
  score: 95.5,

  // Boolean
  verified: true,
  premium: false,

  // Arrays
  tags: ["developer", "graph-db"],
  skills: ["Go", "Cypher", "GraphQL"],

  // Objects
  profile: {
    avatar: "https://example.com/avatar.jpg",
    location: "San Francisco",
    timezone: "PST"
  },

  // Date
  createdAt: datetime("2024-01-15T10:00:00Z")
})

Product Catalog

CREATE (p:Product {
  // Strings
  name: "NornicDB Pro",
  description: "Enterprise graph database",
  sku: "NOR-001",

  // Numbers
  price: 99.99,
  stock: 100,
  rating: 4.8,

  // Boolean
  available: true,
  featured: false,

  // Arrays
  categories: ["database", "graph", "enterprise"],
  images: [
    "https://example.com/img1.jpg",
    "https://example.com/img2.jpg"
  ],

  // Objects
  metadata: {
    weight: 1.5,
    dimensions: {
      width: 10,
      height: 20,
      depth: 5
    },
    manufacturer: {
      name: "NornicDB Inc",
      country: "USA"
    }
  }
})

Event/Calendar

CREATE (e:Event {
  // Strings
  title: "Graph Database Conference",
  description: "Annual conference on graph databases",
  location: "San Francisco Convention Center",

  // Numbers
  capacity: 500,
  price: 299.99,

  // Boolean
  soldOut: false,
  virtual: false,

  // Arrays
  speakers: ["Alice", "Bob", "Carol"],
  tags: ["graph-db", "conference", "networking"],

  // Objects
  schedule: {
    start: datetime("2024-06-15T09:00:00Z"),
    end: datetime("2024-06-17T17:00:00Z"),
    timezone: "PST"
  },

  // Nested objects
  venue: {
    name: "SF Convention Center",
    address: {
      street: "747 Howard St",
      city: "San Francisco",
      state: "CA",
      zip: "94103"
    }
  }
})

Best Practices

1. Use Appropriate Types

  • Use int/int64 for whole numbers (ages, counts, IDs)
  • Use float64 for decimals (prices, measurements, ratings)
  • Use string for text (names, descriptions, codes)
  • Use bool for binary states (flags, toggles)

2. Avoid Type Mixing in Arrays

While []interface{} supports mixed types, prefer homogeneous arrays for clarity:

// ✅ Good: Homogeneous array
tags: ["tag1", "tag2", "tag3"]

// ⚠️ Acceptable but less clear: Mixed array
mixed: ["text", 42, true]

Group related properties in nested objects:

// ✅ Good: Grouped related data
address: {
  street: "123 Main St",
  city: "San Francisco",
  state: "CA"
}

// ❌ Less clear: Flat structure
street: "123 Main St",
city: "San Francisco",
state: "CA"

4. Handle Null Values Explicitly

Use null for optional fields rather than empty strings or zeros:

// ✅ Good: Explicit null for optional field
CREATE (n:Person {
  name: "Alice",
  middleName: null,  // Optional
  age: 30
})

// ❌ Less clear: Using empty string
CREATE (n:Person {
  name: "Alice",
  middleName: "",  // Ambiguous: empty or missing?
  age: 30
})

5. Use Type Constraints for Schema Enforcement

Enforce types at the schema level for data integrity:

// Create constraints
CREATE CONSTRAINT person_age_integer FOR (p:Person) REQUIRE p.age IS INTEGER
CREATE CONSTRAINT person_email_string FOR (p:Person) REQUIRE p.email IS STRING

Limitations & Notes

Storage Limits

  • String length: No hard limit (limited by available memory)
  • Array size: No hard limit (limited by available memory)
  • Object depth: No hard limit (limited by available memory)
  • Property count: No hard limit per node

Type Preservation

  • JSON API: Types may be converted (integers → float64) during JSON round-trip
  • Go API: Types are preserved exactly as provided
  • Cypher: Types are inferred from literals and query context

Vector Embeddings

  • Vector embeddings are not stored as regular properties
  • Use NamedEmbeddings or ChunkEmbeddings struct fields
  • See Vector Embeddings for details

Neo4j Compatibility

  • All Neo4j property types are supported
  • NornicDB extends support for nested objects and arrays
  • Type constraints follow Neo4j syntax


Summary

Supported Types: - ✅ Primitives: string, int/int64, float64/float32, bool, null - ✅ Temporal: time.Time (dates/timestamps) - ✅ Collections: Arrays ([]interface{}, []string, []int, []float64), Maps (map[string]interface{}) - ✅ Nested: Objects can be nested to any depth - ✅ Constraints: Type constraints for schema enforcement

Not Supported as Properties: - ❌ Functions, closures - ❌ Binary data (use base64 strings) - ❌ Circular references (will cause serialization issues)

Best Practices: - Use appropriate types for clarity - Prefer homogeneous arrays - Group related data in nested objects - Use null for optional fields - Enforce types with constraints


Questions? See Complete Examples for real-world usage patterns.