RDF List Access Operations
This guide covers operations for reading elements from RDF lists. These operations allow you to inspect list contents without modifying the underlying structure.
What You'll Learn
- How to read the first element of a list
- How to iterate through all list elements
- How to count list elements
- How to extract slices of lists
- How to access elements by index (nth0/nth1)
Operations Summary
| Operation | Description | Time Complexity |
|---|---|---|
rdflist_peek | Get first element | O(1) |
rdflist_member | Iterate all elements | O(n) |
rdflist_length | Count elements | O(n) |
rdflist_list | Collect all elements as array | O(n) |
rdflist_slice | Extract a range of elements | O(n) |
rdflist_peek
Gets the first element (head) of an RDF list without removing it, or match it with the value in the variable when using as a match operator.
Syntax
WOQL.lib().rdflist_peek(consSubject, valueVar)Parameters
| Parameter | Type | Description |
|---|---|---|
consSubject | string | The list head identifier |
valueVar | string | Variable to bind the first value |
Example
const query = WOQL.lib().rdflist_peek(listHead, "v:first_value");
const result = await client.query(query);
const firstValue = result.bindings[0]["first_value"];
console.log(firstValue["@value"]); // "Task A"Use Cases
- Preview: Check the first item without consuming it
- Stack peek: Implement stack-like peek operations
- Validation: Verify the head element before processing
rdflist_member
Traverses an RDF list and binds each element to a variable through unification. Returns multiple bindings, one for each element. Can be used to both match existing list elements and generate solutions.
Syntax
WOQL.lib().rdflist_member(consSubject, valueVar)Parameters
| Parameter | Type | Description |
|---|---|---|
consSubject | string | The list head identifier |
valueVar | string | Variable to bind each element |
Example
const query = WOQL.lib().rdflist_member(listHead, "v:value");
const result = await client.query(query);
// Returns multiple bindings
const values = result.bindings.map(b => {
const val = b["value"] || b["v:value"];
return val?.["@value"] || val;
});
console.log(values); // ["Task A", "Task B", "Task C"]Use Cases
- Iteration: Process each element in the list
- Search: Find elements matching criteria
- Aggregation: Collect values for further processing
Combining with Other Queries
// Find all tasks with high priority
const query = WOQL.and(
WOQL.lib().rdflist_member(taskListHead, "v:task_id"),
WOQL.triple("v:task_id", "priority", "v:priority"),
WOQL.greater("v:priority", 5)
);rdflist_length
Counts the number of elements in an RDF list, or match that the number of elements match a variable.
Syntax
WOQL.lib().rdflist_length(consSubject, lengthVar)Parameters
| Parameter | Type | Description |
|---|---|---|
consSubject | string | The list head identifier |
lengthVar | string | Variable to bind the count |
Example
const query = WOQL.lib().rdflist_length(listHead, "v:count");
const result = await client.query(query);
const length = parseInt(result.bindings[0]["count"]["@value"]);
console.log(`List has ${length} elements`);Use Cases
- Validation: Check list size constraints
- Pagination: Calculate total pages
- Capacity checks: Verify list doesn't exceed limits
rdflist_list
Collects all elements from an RDF list into a single array in one binding. Can also be used to verify that an RDF list matches a given array.
Syntax
WOQL.lib().rdflist_list(consSubject, listVar)Parameters
| Parameter | Type | Description |
|---|---|---|
consSubject | string | The list head identifier |
listVar | string | Variable to bind the collected array |
Example
const query = WOQL.lib().rdflist_list(listHead, "v:all_items");
const result = await client.query(query);
const items = result.bindings[0]["all_items"];
console.log(items); // [{@value: "A"}, {@value: "B"}, {@value: "C"}]
// Extract values
const values = items.map(item => item?.["@value"] || item);
console.log(values); // ["A", "B", "C"]Use Cases
- Export: Get all list items in one result
- Comparison: Compare entire lists
- Serialization: Convert list to JSON array
Difference from rdflist_member
| Operation | Returns | Bindings |
|---|---|---|
rdflist_member | One element per binding | Multiple bindings |
rdflist_list | All elements as array | Single binding |
rdflist_slice
Extracts a range of elements from an RDF list. Uses 0-based indexing and an exclusive end. Think of the positions to match to be the positions "between" the elements. 0 is before the first element, 1 is after the first element, etc. Thus, to slice the first element, slice between 0 and 1.
Syntax
WOQL.lib().rdflist_slice(consSubject, start, end, resultVar)Parameters
| Parameter | Type | Description |
|---|---|---|
consSubject | string | The list head identifier |
start | number | Start index (0-based, inclusive) |
end | number | End index (exclusive) |
resultVar | string | Variable to bind the slice array |
Examples
// List: [A, B, C, D]
// Get first two elements: slice(0, 2) → [A, B]
const first2 = WOQL.lib().rdflist_slice(listHead, 0, 2, "v:result");
// Get middle elements: slice(1, 3) → [B, C]
const middle = WOQL.lib().rdflist_slice(listHead, 1, 3, "v:result");
// Get last two elements: slice(2, 4) → [C, D]
const last2 = WOQL.lib().rdflist_slice(listHead, 2, 4, "v:result");
// Single element: slice(1, 2) → [B]
const single = WOQL.lib().rdflist_slice(listHead, 1, 2, "v:result");
// Empty slice when start >= end: slice(2, 2) → []
const empty = WOQL.lib().rdflist_slice(listHead, 2, 2, "v:result");Use Cases
- Pagination: Get a page of results
- Preview: Show first N items
- Windowing: Process data in chunks
Accessing Elements by Index
You can use slice instead of nth0 or nth1 operations for single items.
Using Slice for Index Access
// Get element at index 2 (0-based)
const getAt2 = WOQL.lib().rdflist_slice(listHead, 2, 3, "v:element");
const result = await client.query(getAt2);
const element = result.bindings[0]["element"][0]; // First item of single-element arrayUsing Path Queries instead, for manual parsing
Notice that WOQL.path() uses regex style matching (inclusive), whereas slice uses exclusive matching, like in Javascript.
// Access elements by path traversal
// Path {n,n} traverses exactly n rdf:rest links
const pathQuery = WOQL.and(
WOQL.path(listHead, "rdf:rest{2,2}", "v:cell"), // Skip 2 cells
WOQL.triple("v:cell", "rdf:first", "v:value") // Get value
);Zero-Based vs One-Based Indexing
- 0-based (nth0): First element is at index 0
- 1-based (nth1): First element is at index 1
Use slice with appropriate indices:
- nth0(2) = slice(2, 3)[0]
- nth1(2) = slice(1, 2)[0]
Complete Example: List Analysis
List head in the example below is the object of a triple from a list. A list defined on a document/record in TerminusDB will have a triple such as triple("v:docId", "list", "v:listHeadId"). The listHeadId would be what is called a Cons, an rdf:List "construct" that is the start of a list.
import { WOQLClient, WOQL } from "@terminusdb/terminusdb-client";
async function analyzeList(client, listHead) {
// Get list length
const lengthQuery = WOQL.lib().rdflist_length(listHead, "v:len");
const lengthResult = await client.query(lengthQuery);
const length = parseInt(lengthResult.bindings[0]["len"]["@value"]);
console.log(`List length: ${length}`);
if (length === 0) {
console.log("List is empty");
return;
}
// Get first element
const peekQuery = WOQL.lib().rdflist_peek(listHead, "v:first");
const peekResult = await client.query(peekQuery);
console.log(`First element: ${peekResult.bindings[0]["first"]["@value"]}`);
// Get all elements
const listQuery = WOQL.lib().rdflist_list(listHead, "v:all");
const listResult = await client.query(listQuery);
const allItems = listResult.bindings[0]["all"];
console.log("All elements:", allItems.map(i => i["@value"]));
// Get first half
const halfLength = Math.ceil(length / 2);
const sliceQuery = WOQL.lib().rdflist_slice(listHead, 0, halfLength, "v:half");
const sliceResult = await client.query(sliceQuery);
const firstHalf = sliceResult.bindings[0]["half"];
console.log("First half:", firstHalf.map(i => i["@value"]));
}Working with Document References in Lists
// Create tasks
await client.addDocument([
{ "@type": "Task", "@id": "Task/1", title: "Fix bug", priority: 1 },
{ "@type": "Task", "@id": "Task/2", title: "Update docs", priority: 2 }
]);
// Read task details from list
const detailsQuery = WOQL.and(
WOQL.lib().rdflist_member(taskListHead, "v:task_id"),
WOQL.triple("v:task_id", "title", "v:title"),
WOQL.triple("v:task_id", "priority", "v:priority")
);
const details = await client.query(detailsQuery);
// Returns: [{task_id: "Task/1", title: "Fix bug", priority: 1}, ...]Read More
- RDF List Operations Overview - Main guide
- List Creation Operations - Creating lists
- List Modification Operations - Adding and removing elements
- Path Queries - Advanced traversal patterns
- Integration Tests - Complete test examples