---
tags:
  - woql
  - cookbook
  - beginner
title: WOQL Common Patterns
nextjs:
  metadata:
    title: WOQL Common Patterns — 10 Copy-Paste Recipes
    description: Ten practical WOQL query patterns you can copy and adapt — filter, join, aggregate, path query, insert, update, delete, schema query, time-travel, and subgraph queries.
    keywords: woql examples, woql query patterns, terminusdb query tutorial, woql filter, woql join, woql aggregate
    openGraph:
      images: https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png
    alternates:
      canonical: https://terminusdb.com/docs/woql-common-patterns/
media: []
lastUpdated: "2026-05-01"
---

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.

{% callout type="note" %}
**Prerequisites**
Examples use the public Star Wars database. Clone it first:
```bash
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"}'
```
{% /callout %}

---

## 1. Filter by property value

**When to use:** Find documents matching a specific field value.

{% code-tabs %}
{% code-tab label="TypeScript" %}
```typescript
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")
);
```
{% /code-tab %}
{% code-tab label="WOQL AST" %}
```json
{
  "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"}
      }
    ]
  }
}
```
{% /code-tab %}
{% /code-tabs %}

**Expected result:**

```json
[{"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.

{% code-tabs %}
{% code-tab label="TypeScript" %}
```typescript
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")
);
```
{% /code-tab %}
{% code-tab label="WOQL AST" %}
```json
{
  "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"}
      }
    ]
  }
}
```
{% /code-tab %}
{% /code-tabs %}

**Expected result:**

```json
[{"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.

{% code-tabs %}
{% code-tab label="TypeScript" %}
```typescript
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")
);
```
{% /code-tab %}
{% code-tab label="WOQL AST" %}
```json
{
  "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"}
    }
  }
}
```
{% /code-tab %}
{% /code-tabs %}

**Expected result:**

```json
[{"Count": 82}]
```

---

## 4. Path query (follow relationships)

**When to use:** Traverse a chain of relationships — like a recursive JOIN.

{% code-tabs %}
{% code-tab label="TypeScript" %}
```typescript
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")
);
```
{% /code-tab %}
{% code-tab label="WOQL AST" %}
```json
{
  "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"}
      }
    ]
  }
}
```
{% /code-tab %}
{% /code-tabs %}

**Expected result:**

```json
[{"PlanetName": "Tatooine"}]
```

---

## 5. Insert a document

**When to use:** Add a new document to the database.

{% code-tabs %}
{% code-tab label="TypeScript" %}
```typescript
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"
});
```
{% /code-tab %}
{% code-tab label="WOQL AST" %}
```json
{
  "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"}}
        ]
      }
    }
  }
}
```
{% /code-tab %}
{% /code-tabs %}

**Expected result:**

```json
{"bindings": [{}], "inserts": 1, "deletes": 0}
```

{% callout type="note" %}
**Simpler alternative**
For simple inserts, the [Document API](/docs/http-documents-api/) is easier:
`POST /api/document/admin/star_wars/local/branch/main` with the JSON document as body.
{% /callout %}

---

## 6. Update a property

**When to use:** Change a field value on an existing document.

The simplest approach is the Document API with PUT:

```bash
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`:

{% code-tabs %}
{% code-tab label="TypeScript" %}
```typescript
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"
  })
);
```
{% /code-tab %}
{% code-tab label="WOQL AST" %}
```json
{
  "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"}}
            ]
          }
        }
      }
    ]
  }
}
```
{% /code-tab %}
{% /code-tabs %}

**Expected result:**

```json
{"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:

```bash
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`:

{% code-tabs %}
{% code-tab label="TypeScript" %}
```typescript
import TerminusClient from "@terminusdb/terminusdb-client";
const WOQL = TerminusClient.WOQL;

const query = WOQL.delete_document("terminusdb:///data/Planets/1");
```
{% /code-tab %}
{% code-tab label="WOQL AST" %}
```json
{
  "query": {
    "@type": "DeleteDocument",
    "identifier": {"@type": "NodeValue", "node": "terminusdb:///data/Planets/1"}
  }
}
```
{% /code-tab %}
{% /code-tabs %}

**Expected result:**

```json
{"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:

```bash
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:

{% code-tabs %}
{% code-tab label="TypeScript" %}
```typescript
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")
);
```
{% /code-tab %}
{% code-tab label="WOQL AST" %}
```json
{
  "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"}
      }
    ]
  }
}
```
{% /code-tab %}
{% /code-tabs %}

**Expected result:**

```json
[{"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:

```bash
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:

```bash
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.

{% code-tabs %}
{% code-tab label="TypeScript" %}
```typescript
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,
});
```
{% /code-tab %}
{% code-tab label="WOQL AST" %}
```json
// 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=3
```
{% /code-tab %}
{% /code-tabs %}

---

## 10. Find documents within a subgraph

**When to use:** Query only documents linked from a specific root — useful for extracting connected subsets.

{% code-tabs %}
{% code-tab label="TypeScript" %}
```typescript
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")
);
```
{% /code-tab %}
{% code-tab label="WOQL AST" %}
```json
{
  "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"}
      }
    ]
  }
}
```
{% /code-tab %}
{% /code-tabs %}

**Expected result:**

```json
[{"Title": "A New Hope"}, {"Title": "The Empire Strikes Back"}, {"Title": "Return of the Jedi"}, {"Title": "Revenge of the Sith"}]
```

---

## Next steps

- [WOQL Getting Started](/docs/woql-getting-started/) — learn the query language fundamentals
- [WOQL Class Reference](/docs/woql-class-reference-guide/) — complete AST class documentation
- [Version Control Operations](/docs/version-control-operations/) — branch, merge, diff, time-travel
- [Explore the Ecommerce Dataset](/docs/explore-ecommerce-dataset/) — hands-on tutorial with a business dataset
