Ten practical WOQL query patterns you can copy and adapt. Each recipe shows the TypeScript SDK form and the equivalent WOQL AST (JSON) that the API accepts.
Prerequisites Examples use the public Star Wars database. Clone it first:
curl -u admin:root -X POST http://localhost:6363/api/clone/admin/star_wars \
-H "Content-Type: application/json" \
-H "Authorization-Remote: Basic cHVibGljOnB1YmxpYw==" \
-d '{"remote_url": "https://data.terminusdb.org/public/star-wars", "label": "Star Wars"}'1. Filter by property value
When to use: Find documents matching a specific field value.
import TerminusClient from "@terminusdb/terminusdb-client";
const WOQL = TerminusClient.WOQL;
// Find all people with blue eyes
const query = WOQL.and(
WOQL.triple("v:Person", "rdf:type", "@schema:People"),
WOQL.triple("v:Person", "eye_color", WOQL.string("blue")),
WOQL.triple("v:Person", "name", "v:Name")
);{
"query": {
"@type": "And",
"and": [
{
"@type": "Triple",
"subject": {"@type": "NodeValue", "variable": "Person"},
"predicate": {"@type": "NodeValue", "node": "rdf:type"},
"object": {"@type": "NodeValue", "node": "@schema:People"}
},
{
"@type": "Triple",
"subject": {"@type": "NodeValue", "variable": "Person"},
"predicate": {"@type": "NodeValue", "node": "eye_color"},
"object": {"@type": "DataValue", "data": "blue"}
},
{
"@type": "Triple",
"subject": {"@type": "NodeValue", "variable": "Person"},
"predicate": {"@type": "NodeValue", "node": "name"},
"object": {"@type": "DataValue", "variable": "Name"}
}
]
}
}Expected result:
[{"Name": "Luke Skywalker"}, {"Name": "Owen Lars"}, {"Name": "Beru Whitesun lars"}, {"Name": "Anakin Skywalker"}]2. Join two document types
When to use: Traverse a relationship between documents — no JOIN syntax needed, just follow the link.
import TerminusClient from "@terminusdb/terminusdb-client";
const WOQL = TerminusClient.WOQL;
// Find people and their homeworld name
const query = WOQL.and(
WOQL.triple("v:Person", "rdf:type", "@schema:People"),
WOQL.triple("v:Person", "name", "v:PersonName"),
WOQL.triple("v:Person", "homeworld", "v:Planet"),
WOQL.triple("v:Planet", "name", "v:PlanetName")
);{
"query": {
"@type": "And",
"and": [
{
"@type": "Triple",
"subject": {"@type": "NodeValue", "variable": "Person"},
"predicate": {"@type": "NodeValue", "node": "rdf:type"},
"object": {"@type": "NodeValue", "node": "@schema:People"}
},
{
"@type": "Triple",
"subject": {"@type": "NodeValue", "variable": "Person"},
"predicate": {"@type": "NodeValue", "node": "name"},
"object": {"@type": "DataValue", "variable": "PersonName"}
},
{
"@type": "Triple",
"subject": {"@type": "NodeValue", "variable": "Person"},
"predicate": {"@type": "NodeValue", "node": "homeworld"},
"object": {"@type": "NodeValue", "variable": "Planet"}
},
{
"@type": "Triple",
"subject": {"@type": "NodeValue", "variable": "Planet"},
"predicate": {"@type": "NodeValue", "node": "name"},
"object": {"@type": "DataValue", "variable": "PlanetName"}
}
]
}
}Expected result:
[{"PersonName": "Luke Skywalker", "PlanetName": "Tatooine"}, {"PersonName": "Darth Vader", "PlanetName": "Tatooine"}, {"PersonName": "Leia Organa", "PlanetName": "Alderaan"}]3. Aggregate (count)
When to use: Count documents matching a condition.
import TerminusClient from "@terminusdb/terminusdb-client";
const WOQL = TerminusClient.WOQL;
// Count all people
const query = WOQL.count("v:Count",
WOQL.triple("v:Person", "rdf:type", "@schema:People")
);{
"query": {
"@type": "Count",
"count": {"@type": "DataValue", "variable": "Count"},
"query": {
"@type": "Triple",
"subject": {"@type": "NodeValue", "variable": "Person"},
"predicate": {"@type": "NodeValue", "node": "rdf:type"},
"object": {"@type": "NodeValue", "node": "@schema:People"}
}
}
}Expected result:
[{"Count": 82}]4. Path query (follow relationships)
When to use: Traverse a chain of relationships — like a recursive JOIN.
import TerminusClient from "@terminusdb/terminusdb-client";
const WOQL = TerminusClient.WOQL;
// Find all planets reachable from a person via homeworld links
const query = WOQL.and(
WOQL.triple("v:Person", "name", WOQL.string("Luke Skywalker")),
WOQL.path("v:Person", "homeworld", "v:Planet", "v:Path"),
WOQL.triple("v:Planet", "name", "v:PlanetName")
);{
"query": {
"@type": "And",
"and": [
{
"@type": "Triple",
"subject": {"@type": "NodeValue", "variable": "Person"},
"predicate": {"@type": "NodeValue", "node": "name"},
"object": {"@type": "DataValue", "data": "Luke Skywalker"}
},
{
"@type": "Path",
"subject": {"@type": "Value", "variable": "Person"},
"pattern": {"@type": "PathPredicate", "predicate": "homeworld"},
"object": {"@type": "Value", "variable": "Planet"},
"path": {"@type": "Value", "variable": "Path"}
},
{
"@type": "Triple",
"subject": {"@type": "NodeValue", "variable": "Planet"},
"predicate": {"@type": "NodeValue", "node": "name"},
"object": {"@type": "DataValue", "variable": "PlanetName"}
}
]
}
}Expected result:
[{"PlanetName": "Tatooine"}]5. Insert a document
When to use: Add a new document to the database.
import TerminusClient from "@terminusdb/terminusdb-client";
const WOQL = TerminusClient.WOQL;
const query = WOQL.insert_document({
"@type": "Planets",
"name": "Mandalore",
"climate": "temperate",
"terrain": "forests, jungles",
"population": "4200000000"
});{
"query": {
"@type": "InsertDocument",
"document": {
"@type": "Value",
"dictionary": {
"@type": "DictionaryTemplate",
"data": [
{"@type": "FieldValuePair", "field": "@type", "value": {"@type": "Value", "data": "Planets"}},
{"@type": "FieldValuePair", "field": "name", "value": {"@type": "Value", "data": "Mandalore"}},
{"@type": "FieldValuePair", "field": "climate", "value": {"@type": "Value", "data": "temperate"}},
{"@type": "FieldValuePair", "field": "terrain", "value": {"@type": "Value", "data": "forests, jungles"}},
{"@type": "FieldValuePair", "field": "population", "value": {"@type": "Value", "data": "4200000000"}}
]
}
}
}
}Expected result:
{"bindings": [{}], "inserts": 1, "deletes": 0}Simpler alternative For simple inserts, the Document API is easier: POST /api/document/admin/star_wars/local/branch/main with the JSON document as body.
6. Update a property
When to use: Change a field value on an existing document.
The simplest approach is the Document API with PUT:
curl -u admin:root -X PUT \
"http://localhost:6363/api/document/admin/star_wars/local/branch/main?author=admin&message=Update+Tatooine+climate" \
-H "Content-Type: application/json" \
-d '{"@id": "Planets/1", "@type": "Planets", "name": "Tatooine", "climate": "hot and arid", "terrain": "desert", "population": "200000"}'For conditional updates, use WOQL's update_document:
import TerminusClient from "@terminusdb/terminusdb-client";
const WOQL = TerminusClient.WOQL;
const query = WOQL.and(
WOQL.read_document("terminusdb:///data/Planets/1", "v:Doc"),
WOQL.update_document({
"@id": "Planets/1",
"@type": "Planets",
"name": "Tatooine",
"climate": "hot and arid",
"terrain": "desert",
"population": "200000"
})
);{
"query": {
"@type": "And",
"and": [
{
"@type": "ReadDocument",
"identifier": {"@type": "NodeValue", "node": "terminusdb:///data/Planets/1"},
"document": {"@type": "Value", "variable": "Doc"}
},
{
"@type": "UpdateDocument",
"document": {
"@type": "Value",
"dictionary": {
"@type": "DictionaryTemplate",
"data": [
{"@type": "FieldValuePair", "field": "@id", "value": {"@type": "Value", "data": "Planets/1"}},
{"@type": "FieldValuePair", "field": "@type", "value": {"@type": "Value", "data": "Planets"}},
{"@type": "FieldValuePair", "field": "name", "value": {"@type": "Value", "data": "Tatooine"}},
{"@type": "FieldValuePair", "field": "climate", "value": {"@type": "Value", "data": "hot and arid"}},
{"@type": "FieldValuePair", "field": "terrain", "value": {"@type": "Value", "data": "desert"}},
{"@type": "FieldValuePair", "field": "population", "value": {"@type": "Value", "data": "200000"}}
]
}
}
}
]
}
}Expected result:
{"bindings": [{}], "inserts": 1, "deletes": 1}7. Delete a document
When to use: Remove a document from the database.
The simplest approach is the Document API with DELETE:
curl -u admin:root -X DELETE \
"http://localhost:6363/api/document/admin/star_wars/local/branch/main?id=terminusdb:///data/Planets/1&author=admin&message=Remove+Tatooine"For conditional deletion, use WOQL's delete_document:
import TerminusClient from "@terminusdb/terminusdb-client";
const WOQL = TerminusClient.WOQL;
const query = WOQL.delete_document("terminusdb:///data/Planets/1");{
"query": {
"@type": "DeleteDocument",
"identifier": {"@type": "NodeValue", "node": "terminusdb:///data/Planets/1"}
}
}Expected result:
{"bindings": [{}], "inserts": 0, "deletes": 1}8. Query schema classes
When to use: List all document types defined in the schema.
The simplest approach is the Document API:
curl -u admin:root \
"http://localhost:6363/api/document/admin/star_wars/local/branch/main?graph_type=schema&as_list=true"For specific class properties, use WOQL with the schema graph:
import TerminusClient from "@terminusdb/terminusdb-client";
const WOQL = TerminusClient.WOQL;
// Find all classes and their fields
const query = WOQL.and(
WOQL.quad("v:Class", "rdf:type", "sys:Class", "schema"),
WOQL.triple("v:Class", "name", "v:ClassName")
);{
"query": {
"@type": "And",
"and": [
{
"@type": "Quad",
"subject": {"@type": "NodeValue", "variable": "Class"},
"predicate": {"@type": "NodeValue", "node": "rdf:type"},
"object": {"@type": "NodeValue", "node": "sys:Class"},
"graph": "schema"
},
{
"@type": "Triple",
"subject": {"@type": "NodeValue", "variable": "Class"},
"predicate": {"@type": "NodeValue", "node": "name"},
"object": {"@type": "DataValue", "variable": "ClassName"}
}
]
}
}Expected result:
[{"Class": "People", "ClassName": "People"}, {"Class": "Planets", "ClassName": "Planets"}, {"Class": "Films", "ClassName": "Films"}]9. Time-travel (query at a previous commit)
When to use: See the database state at any point in history — without modifying anything.
First, get the commit history:
curl -u admin:root "http://localhost:6363/api/log/admin/star_wars/local/branch/main?count=3"Then query at a specific commit by using the commit path:
curl -u admin:root \
"http://localhost:6363/api/document/admin/star_wars/local/commit/{commit_id}?type=People&as_list=true"Replace {commit_id} with the commit identifier from the log. You see the exact state at that moment — a snapshot frozen in time.
import TerminusClient from "@terminusdb/terminusdb-client";
const client = new TerminusClient.WOQLClient("http://localhost:6363", {
user: "admin",
key: "root",
organization: "admin",
db: "star_wars",
});
// Get commit history
const log = await client.getCommitHistory();
const previousCommit = log[1].identifier;
// Query at that commit
const docs = await client.getDocument({
type: "People",
as_list: true,
commit: previousCommit,
});// Time-travel uses the Document API with a commit path, not WOQL.
// GET /api/document/{org}/{db}/local/commit/{commit_id}?type=People&as_list=true
//
// The commit_id comes from the log:
// GET /api/log/{org}/{db}/local/branch/main?count=310. Find documents within a subgraph
When to use: Query only documents linked from a specific root — useful for extracting connected subsets.
import TerminusClient from "@terminusdb/terminusdb-client";
const WOQL = TerminusClient.WOQL;
// Find all films that a specific person appears in
const query = WOQL.and(
WOQL.triple("v:Person", "name", WOQL.string("Luke Skywalker")),
WOQL.triple("v:Film", "characters", "v:Person"),
WOQL.triple("v:Film", "title", "v:Title")
);{
"query": {
"@type": "And",
"and": [
{
"@type": "Triple",
"subject": {"@type": "NodeValue", "variable": "Person"},
"predicate": {"@type": "NodeValue", "node": "name"},
"object": {"@type": "DataValue", "data": "Luke Skywalker"}
},
{
"@type": "Triple",
"subject": {"@type": "NodeValue", "variable": "Film"},
"predicate": {"@type": "NodeValue", "node": "characters"},
"object": {"@type": "NodeValue", "variable": "Person"}
},
{
"@type": "Triple",
"subject": {"@type": "NodeValue", "variable": "Film"},
"predicate": {"@type": "NodeValue", "node": "title"},
"object": {"@type": "DataValue", "variable": "Title"}
}
]
}
}Expected result:
[{"Title": "A New Hope"}, {"Title": "The Empire Strikes Back"}, {"Title": "Return of the Jedi"}, {"Title": "Revenge of the Sith"}]Next steps
- WOQL Getting Started — learn the query language fundamentals
- WOQL Class Reference — complete AST class documentation
- Version Control Operations — branch, merge, diff, time-travel
- Explore the Ecommerce Dataset — hands-on tutorial with a business dataset