This guide shows how to execute WOQL queries using raw JSON-LD format with the JavaScript client, enabling you to use new server features even before they have corresponding helper methods in the client library.
Why Use JSON-LD Queries?
While the WOQL JavaScript API provides convenient builder methods like WOQL.triple() and WOQL.and(), there are scenarios where using raw JSON-LD queries is useful:
- Early Adoption: Use new server features before the client library adds helper methods
- Debugging: Inspect the exact query structure being sent to the server
- Testing: Validate server behavior with precise JSON-LD queries
- Migration: Port queries from other clients or documentation examples
- Advanced Features: Access experimental or specialized functionality
The WOQL JSON-LD Format
Internally, all WOQL queries are represented as JSON-LD (JSON for Linked Data) before being sent to the TerminusDB server. The client's builder methods simply provide a convenient way to construct this JSON-LD, such as for the Javascript and Python clients.
Example: Simple Triple Query
WOQL Builder Syntax:
WOQL.triple('v:Person', 'rdf:type', '@schema:Person')Equivalent JSON-LD:
{
"@type": "Triple",
"subject": {
"@type": "NodeValue",
"variable": "Person"
},
"predicate": {
"@type": "NodeValue",
"node": "rdf:type"
},
"object": {
"@type": "NodeValue",
"node": "@schema:Person"
}
}Executing JSON-LD Queries
The JavaScript client's query() method accepts both WOQLQuery objects and raw JSON-LD objects.
Method 1: Direct JSON-LD with client.query()
Pass the JSON-LD object directly to client.query():
const { WOQLClient } = require('terminusdb');
const client = new WOQLClient('http://127.0.0.1:6363', {
user: 'admin',
organization: 'admin',
key: 'root'
});
// Raw JSON-LD query
const jsonQuery = {
"@type": "And",
"and": [
{
"@type": "Triple",
"subject": { "@type": "NodeValue", "variable": "Person" },
"predicate": { "@type": "NodeValue", "node": "rdf:type" },
"object": { "@type": "NodeValue", "node": "@schema:Person" }
},
{
"@type": "Triple",
"subject": { "@type": "NodeValue", "variable": "Person" },
"predicate": { "@type": "NodeValue", "node": "@schema:name" },
"object": { "@type": "NodeValue", "variable": "Name" }
}
]
};
const result = await client.query(jsonQuery);
console.log(result.bindings);Method 2: Using WOQLQuery().json()
Convert between WOQL builder syntax and JSON-LD using the json() method:
const { WOQL } = require('terminusdb');
// Convert WOQL to JSON-LD
const woqlQuery = WOQL.triple('v:Person', 'rdf:type', '@schema:Person');
const jsonLD = woqlQuery.json();
console.log(JSON.stringify(jsonLD, null, 2));
// Convert JSON-LD to WOQL
const fromJSON = new WOQLQuery().json(jsonLD);
const result = await client.query(fromJSON);Real-World Example: RandomKey Before Client Support
Before the random_idgen() method was added to the JavaScript client, you could still use the RandomKey feature by passing the JSON-LD directly:
// Using RandomKey with raw JSON-LD (works even without client helper)
const randomKeyQuery = {
"@type": "RandomKey",
"base": {
"@type": "DataValue",
"data": { "@type": "xsd:string", "@value": "Person/" }
},
"uri": {
"@type": "NodeValue",
"variable": "person_id"
}
};
const result = await client.query(randomKeyQuery);
console.log(result.bindings[0].person_id);
// Output: "Person/aB3dEf9GhI2jK4lM" (random ID generated)This is equivalent to using the client helper (once it's available):
const result = await client.query(
WOQL.random_idgen('Person/', 'v:person_id')
);Mixing JSON-LD with WOQL Builder
You can embed JSON-LD within WOQL builder queries for hybrid approaches:
const query = WOQL.and(
// Use builder method
WOQL.triple('v:Person', 'rdf:type', '@schema:Person'),
// Embed raw JSON-LD for new feature
{
"@type": "RandomKey",
"base": {
"@type": "DataValue",
"data": { "@type": "xsd:string", "@value": "Person/" }
},
"uri": { "@type": "NodeValue", "variable": "new_id" }
}
);
const result = await client.query(query);Common WOQL JSON-LD Patterns
Data Values
String, number, and other literal values use DataValue:
{
"@type": "DataValue",
"data": {
"@type": "xsd:string",
"@value": "Alice"
}
}For numbers:
{
"@type": "DataValue",
"data": {
"@type": "xsd:integer",
"@value": 42
}
}Node Values (Variables and IRIs)
Variables:
{
"@type": "NodeValue",
"variable": "Person"
}IRIs/Nodes:
{
"@type": "NodeValue",
"node": "@schema:Person"
}Compound Queries
And:
{
"@type": "And",
"and": [
{ /* query 1 */ },
{ /* query 2 */ }
]
}Or:
{
"@type": "Or",
"or": [
{ /* query 1 */ },
{ /* query 2 */ }
]
}Select (variable projection):
{
"@type": "Select",
"variables": ["Name", "Age"],
"query": { /* subquery */ }
}Converting Existing Queries to JSON-LD
To see the JSON-LD for any WOQL query, use the json() method:
const woqlQuery = WOQL.select('v:Name', 'v:Age').and(
WOQL.triple('v:Person', 'rdf:type', '@schema:Person'),
WOQL.triple('v:Person', '@schema:name', 'v:Name'),
WOQL.triple('v:Person', '@schema:age', 'v:Age')
);
// View the JSON-LD
console.log(JSON.stringify(woqlQuery.json(), null, 2));This outputs the complete JSON-LD structure you can use directly with client.query().
Tips and Best Practices
1. Start with Builder, Convert to JSON-LD
When learning the JSON-LD format, start with the builder syntax and use json() to see the structure:
const builderQuery = WOQL.limit(10).triple('v:X', 'v:Y', 'v:Z');
console.log(JSON.stringify(builderQuery.json(), null, 2));2. Validate JSON-LD Structure
Use the WOQL schema definition to validate your JSON-LD:
- Server schema:
/path/to/terminusdb/src/terminus-schema/woql.json - Ensures correct
@typevalues and required fields
3. Handle Variable Names
Variables in JSON-LD don't use the v: prefix - just the name:
{
"@type": "NodeValue",
"variable": "Person" // Not "v:Person"
}But in the builder syntax, you use 'v:Person' or the vars() helper.
4. Use for Integration Tests
JSON-LD queries are excellent for integration tests as they're explicit and version-independent:
describe('RandomKey functionality', () => {
it('generates unique IDs', async () => {
const query = {
"@type": "RandomKey",
"base": {
"@type": "DataValue",
"data": { "@type": "xsd:string", "@value": "Test/" }
},
"uri": { "@type": "NodeValue", "variable": "id" }
};
const result = await client.query(query);
expect(result.bindings[0].id).to.include('Test/');
});
});Error Handling
When using raw JSON-LD, be aware of common errors:
Missing Required Fields
{
"@type": "Triple"
// Error: Missing subject, predicate, object
}Incorrect Types
{
"@type": "TriplePattern", // Error: Should be "Triple"
// ...
}Invalid Variable/Node Specification
{
"@type": "NodeValue",
"var": "Person" // Error: Should be "variable" not "var"
}The server will return detailed error messages indicating which field is problematic.
Finding JSON-LD Examples
Several sources provide JSON-LD query examples:
- Client Test Suites: Look at test files in
terminusdb-client-js/test/woqlJson/ - Server Tests: Check
terminusdb/tests/test/for integration test examples - WOQL Schema: Review
terminusdb/src/terminus-schema/woql.jsonfor all query types - Use json() Method: Convert any builder query to see its JSON-LD structure
Related Documentation
- WOQL Basics - Learn the WOQL builder API
- WOQL Explanation - Understanding WOQL and JSON-LD
- JavaScript Client Reference - Complete API reference
- WOQL Schema Reference - WOQL JSON-LD specification
Summary
Raw JSON-LD queries provide a powerful way to:
- Access new server features immediately
- Debug and understand query structures
- Create integration tests
- Port queries between different clients
While the WOQL builder API is more convenient for everyday use, understanding and using JSON-LD directly gives you full control and enables early adoption of new TerminusDB features.