TuringDB home pagelight logodark logo
  • Discord
  • GitHub
  • Website
TuringDB

Get Started

  • Introduction
  • Get Started
  • Claude Code Skill
  • Commands

Concepts

  • Overview
  • A Columnar Graph Database
  • Versioning System
  • The DataPart System
  • Zero-Locking Architecture
  • Snapshots Isolation

Benchmarks

  • Results Summary
  • Technical Report

Query Language

  • Overview
  • Matching
  • Paths
  • Results and Aggregation
  • Subqueries
  • Functions and Types
  • Writing Data
  • Procedures and Commands
  • CheatSheet

Importing data

  • JSONL
  • CSV
  • Neo4j
  • GML
  • Parquet

Graph Development

  • Create Graph
  • Load Graph
  • Load External data
  • Create a Change
  • List Changes
  • Create Nodes and Edges
  • Update Properties
  • Submit a Change
  • Time Travel
  • Graph Examples

Vector Search

  • Vector Search

Graph Algorithms

  • Shortest Path

Tutorials

  • Example Notebooks

Python SDK

  • Get Started
  • Reference

Troubleshooting

  • Troubleshooting

  • What is supported
  • Basics
  • Running a query
  • Coming from Neo4j
  • Data types
  • Roadmap
Query Language

Query Language in TuringDB

TuringDB v3 runs Cypher on a new engine and supports most of openCypher: OPTIONAL MATCH, WITH, UNWIND, UNION, MERGE, variable-length paths, subqueries and more.

TuringDB v3 (turingdb 3.0 on PyPI) runs every query on a new MLIR-based engine and supports most of openCypher, extended with versioning, vector search and fast lookup by native node ID.

If you know Cypher from Neo4j, you can write the queries you are used to. This page covers the basics and the handful of places where TuringDB differs. The rest of the language is documented in the pages that follow.

​
What is supported

AreaSupported
ReadingMATCH, OPTIONAL MATCH, WHERE, WITH, RETURN [DISTINCT], ORDER BY, SKIP, LIMIT, UNWIND, UNION [ALL], LOAD CSV
PatternsMultiple labels, edge type alternatives ([:A|B]), inline WHERE, variable-length paths (*1..3, ->+, {2,4}), quantified path patterns, named paths, pattern predicates
ExpressionsArithmetic, string and list concatenation, CASE, list and pattern comprehensions, reduce, all / any / none / single, list slicing, maps
Aggregationcount, sum, avg, min, max, collect, DISTINCT, implicit grouping, aggregates inside expressions
SubqueriesEXISTS { }, COUNT { }, CALL { } and OPTIONAL CALL { }
WritingCREATE, MERGE with ON CREATE / ON MATCH, SET, REMOVE, DELETE, DETACH DELETE
TypesString, Integer, Double, Boolean, List, Map, DateTime, Duration, Embedding
TuringDB extrasChanges, commits and time travel, shortestPath, VECTOR SEARCH, gnn.graphSAGE, lookup by native node ID

​
Basics

Queries are built from nodes and edges:

  • Nodes are written in parentheses: (n) is a node named n.
  • Edges are written in square brackets: [e] is an edge named e.
  • Labels are added with a colon: (n:Person). A node can have several: (n:Person:Employee).
  • Edge types use the same syntax: [e:FRIENDS_WITH]. An edge has exactly one edge type.
  • Properties are constrained with curly braces: (n:Person {name: 'John', age: 20}).
MATCH (a:Person {name: 'Alice'})-[e:KNOWS]->(b:Person)
RETURN a.name, e.since, b.name

By convention, node labels are written in PascalCase (Person, BankAccount), edge types in upper case with underscores (WORKS_AT, FRIENDS_WITH), and strings use single quotes.

Keywords are case-insensitive (MATCH and match are the same). Labels, edge types and property names are case-sensitive. Only // starts a comment:

// a line comment
MATCH (n:Person) RETURN n.name // also fine at the end of a line

Use // for comments. SQL-style -- and /* */ comments are not yet supported.

​
Running a query

Queries run through the Python SDK, the interactive shell, or the HTTP endpoint. Read queries run directly against the current graph; write queries must run inside a change.

from turingdb import TuringDB

client = TuringDB(host="http://localhost:6666")
df = client.query("MATCH (n:Person) RETURN n.name, n.age")   # a pandas DataFrame

EXPLAIN <query> returns the compiled query plan without running the query. It is the easiest way to check that a lookup uses a constant node scan.

​
Coming from Neo4j

TuringDB follows openCypher closely, so the queries you know carry over. These are the TuringDB specifics worth knowing:

  • RETURN n returns the node’s internal ID, an integer. Return the properties you need with RETURN n.name, n.age, or use db.getNodes to see every property of a few nodes.
  • Values go in the query text. Queries are plain strings, so put literal values directly in the text and escape quotes in your application. Query parameters such as $name are not yet supported.
  • One statement per request. Send each statement as its own request (a single trailing ; is fine).
  • Labels are set at creation. Every node has at least one label and every edge exactly one edge type, chosen when it is created.
  • Property types are global. A property name has a single value type across the whole graph: if age is an Integer, it is an Integer on every node.
  • Typed numeric equality. Compare Integers with Integers, and match Doubles with a range (n.score > 1.99 AND n.score < 2.01) or convert with toInteger. <, > and arithmetic work across numeric types.
  • Forgiving names. An unknown label matches nothing and a misspelled property reads as null. Check names with CALL db.labels() and CALL db.propertyTypes().
  • Label alternatives. Write WHERE n:A OR n:B or WHERE NOT n:A. Edge type alternatives ([:A|B]) work directly in patterns.
  • String matching. Use STARTS WITH, ENDS WITH and CONTAINS. Regular expressions (=~) are not yet supported.
  • Loops and uniqueness. Use UNWIND for loops and MERGE to avoid duplicates.
  • Shortest paths use a TuringDB statement, see Shortest path.
  • Function names are case-sensitive (toInteger, not TOINTEGER), except count and collect.

Coming from TuringDB 1.x? The v3 engine replaces the previous one, and many earlier limits are gone: OPTIONAL MATCH, WITH, DISTINCT, UNION, MERGE, DELETE, aggregates in any position, UNWIND over any list, LOAD CSV followed by MATCH, and CREATE ... SET all work now. One function changed name: edgeType(e) is now type(e).

​
Data types

TuringDB offers these types for node and edge properties and for values in queries:

TypeLiteralNotes
String'Alice' or "Alice"Backslash escapes (\'). Backticks quote identifiers, not strings
Integer30, 0x1FSigned 64-bit. Integer division truncates
Double3.14, 1e3^ always returns a Double
Booleantrue, false
List[1, 'a', [2]]May mix types and nest
Map{a: 1, b: [1, 2]}See Maps
DateTimedatetime('2024-03-15T10:30:00Z')Microsecond precision, always UTC
Durationduration({days: 2})Microsecond precision, no month component
Embedding(1.2, 2.0, 0.0)Parentheses, at least 2 numbers. See Vector search

Embedding literals use parentheses. [1.2, 2.0, 0.0] is a List, which is a different type.

More detail on types, conversion and results is in Functions and data types.

​
Roadmap

We keep extending Cypher coverage and growing the library of procedures available through CALL. If there is a query form you would like to see, please tell us.

Technical ReportMatching
githublinkedinyoutubediscord