--- title: WOQL Variable Generation Guide (Javascript) nextjs: metadata: title: WOQL Variable Generation - vars, vars_unique, Vars, and VarsUnique description: Complete guide to the four variable generation methods in the TerminusDB JavaScript client - vars, vars_unique, Vars, and VarsUnique - with practical examples and use cases openGraph: images: https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png alternates: canonical: https://terminusdb.org/docs/woql-variable-generation/ media: [] --- When writing WOQL queries with the JavaScript client, you need to create variables to bind values, pass data between query operations, and return results. TerminusDB provides **four distinct methods** for generating variables, each optimized for different coding styles and use cases. This guide explains when and how to use `vars()`, `vars_unique()`, `Vars()`, and `VarsUnique()` in the javascript client. ## Quick Overview | Method | Returns | Naming | Use Case | |--------|---------|--------|----------| | `vars()` | Array | Exact names | Simple queries, array destructuring | | `vars_unique()` | Array | Auto-suffixed | Prevent naming conflicts, local scopes | | `Vars()` | Object | Exact names | Complex queries, object property access | | `VarsUnique()` | Object | Auto-suffixed | Complex queries with local scopes | ## Understanding Variable Generation ### Why Do We Need Variables? In WOQL queries, variables act as placeholders that bind to values during query execution. Variables are used with [unification](/docs/unification/), where variables get resolved and bind to values and constrain the query during the unfolding of the query resolution. ```javascript const [person, name] = WOQL.vars("Person", "Name"); WOQL.select([person, name], WOQL.triple(person, "rdf:type", "@schema:Person"), WOQL.triple(person, "name", name) ); ``` The variables `person` and `name` will hold the results returned by the query. ### The Four Generation Methods TerminusDB offers two **access patterns** (array vs. object) and two **naming strategies** (exact vs. unique): **Access Patterns:** - **Array-based** (`vars`, `vars_unique`) - Use array destructuring - **Object-based** (`Vars`, `VarsUnique`) - Use property access with dot notation **Naming Strategies:** - **Exact names** (`vars`, `Vars`) - Variables have exactly the names you specify - **Unique names** (`vars_unique`, `VarsUnique`) - Variables get auto-incremented suffixes ## Object-Based Variables ### Vars() - Variable Object with Exact Names The `Vars()` function returns an object where each property is a variable. Access variables using dot notation. Names are exacly as specified which is important for getting consistent binding results from queries. These are the best to learn with. **Syntax:** ```javascript const v = WOQL.Vars("var1", "var2", "var3"); // Access as: v.var1, v.var2, v.var3 ``` **When to Use:** - Complex queries with many variables - Better code organization and readability - Self-documenting code - Top level query bindings variables (for the resulting tabular structure) - Avoiding long destructuring assignments **Example - Clean Query Structure:** ```javascript const v = WOQL.Vars("person", "name", "email", "age", "city"); const query = WOQL.select([v.person, v.name, v.email], WOQL.and( WOQL.triple(v.person, "rdf:type", "@schema:Person"), WOQL.triple(v.person, "name", v.name), WOQL.triple(v.person, "email", v.email), WOQL.triple(v.person, "age", v.age), WOQL.triple(v.person, "city", v.city), WOQL.greater(v.age, 18) ) ); ``` **Example - Multiple Variable Groups:** ```javascript // Organize variables by domain const person = WOQL.Vars("id", "name", "email"); const address = WOQL.Vars("street", "city", "country"); const order = WOQL.Vars("orderId", "total", "date"); const query = WOQL.and( WOQL.triple(person.id, "name", person.name), WOQL.triple(person.id, "email", person.email), WOQL.triple(person.id, "address", address.street), WOQL.triple(order.orderId, "customer", person.id), WOQL.triple(order.orderId, "total", order.total) ); ``` **Example - Arithmetic with Object Variables:** ```javascript const v = WOQL.Vars("result1", "result2"); const query = WOQL.and( WOQL.eval(WOQL.times(2, 3), v.result1), WOQL.eval(WOQL.plus(10, 5), v.result2) ); await client.query(query); // Returns: [{ result1: 6, result2: 15 }] ``` **Key Characteristics:** - ✅ Cleaner code with dot notation - ✅ Better for complex queries - ✅ Self-documenting variable access - ✅ No long destructuring lines - ✅ Easy to pass variable groups around - ⚠️ Slightly more verbose initialization ### VarsUnique() - Variable Object with Unique Names The `VarsUnique()` function combines object-based access with automatic name uniqueness. This is important for deep nested queries where locally scoped variables are important (in combination with the select predicate). For advanced use cases. **Syntax:** ```javascript const v = WOQL.VarsUnique("var1", "var2", "var3"); // Access as: v.var1, v.var2, v.var3 // Actual names: var1_N, var2_M, var3_P (with unique suffixes) ``` **When to Use:** - Complex queries needing local scopes - Building reusable query components - Preventing variable conflicts in large codebases - Nested query operations with `select()` **Example - Local Scoped Variables:** ```javascript const v = WOQL.VarsUnique("result1", "result2"); const query = WOQL.limit(100).eval(WOQL.times(2, 3), v.result1); await client.query(query); // Returns: [{ result1_21: { "@type": "xsd:decimal", "@value": 6 }}] // The suffix ensures uniqueness ``` **Example - Nested Query Scopes:** ```javascript // Outer scope const outer = WOQL.VarsUnique("person", "name"); // Inner scope - won't conflict even if using same names const inner = WOQL.VarsUnique("person", "detail"); const query = WOQL.and( WOQL.triple(outer.person, "name", outer.name), WOQL.select([inner.person, inner.detail], WOQL.triple(inner.person, "detail", inner.detail) ) ); // outer.person and inner.person have different actual names ``` **Example - Reusable Query Functions:** ```javascript function createPersonQuery() { // Each call gets local unique variables (eq can be used to bind variables together) const v = WOQL.VarsUnique("person", "name", "email"); return WOQL.and( WOQL.triple(v.person, "rdf:type", "@schema:Person"), WOQL.triple(v.person, "name", v.name), WOQL.triple(v.person, "email", v.email) ); } // Use multiple times without conflicts const query1 = createPersonQuery(); const query2 = createPersonQuery(); const combined = WOQL.and(query1, query2); // No variable conflicts! ``` **Key Characteristics:** - ✅ Clean object-based access - ✅ Automatic name uniqueness - ✅ Perfect for reusable components - ✅ Excellent for nested scopes - ✅ Prevents conflicts in large queries - ✅ Combine with `eq()` to connect local and global scoped variables - ⚠️ Result keys include suffixes - ⚠️ Be careful with changing variable names as the object keys will change too - ⚠️ Less predictable variable names in bindings ## Array-Based Variables Array-based variables makes for neater WOQL, removing the need for the `v.` prefix with a one to one mapping between WOQL variable names and the javascript variable names. ### vars() - Simple Array Variables The `vars()` function creates an array of variables with exact names. **Syntax:** ```javascript const [var1, var2, var3] = WOQL.vars("varName1", "varName2", "varName3"); ``` **When to Use:** - Simple queries with few variables - When you want exact control over variable names - Quick prototypes and examples **Example - Basic Query:** ```javascript const [person, name, age] = WOQL.vars("Person", "Name", "Age"); const query = WOQL.select([person, name, age], WOQL.triple(person, "rdf:type", "@schema:Person"), WOQL.triple(person, "name", name), WOQL.triple(person, "age", age) ); const result = await client.query(query); // Result bindings use exact names: { Person: ..., Name: ..., Age: ... } ``` **Example - Mathematical Operations:** ```javascript const [result] = WOQL.vars("result"); // Remember that the mathematical evaluation is performed on the server side! const query = WOQL.eval( WOQL.times(2, 3), result ); await client.query(query); // Returns: [{ result: { "@type": "xsd:decimal", "@value": 6 }}] ``` **Key Characteristics:** - ✅ Simple and intuitive - ✅ Variables have exactly the names you provide - ✅ Perfect for straightforward queries - ⚠️ No protection against name collisions - ⚠️ Manual tracking required in complex queries ### vars_unique() - Uniquely Named Array Variables The `vars_unique()` function creates variables with automatically incremented suffixes (e.g., `result_1`, `result_2`). **Syntax:** ```javascript const [var1, var2] = WOQL.vars_unique("varName1", "varName2"); // Creates: varName1_1, varName2_2 (numbers increment globally) ``` **When to Use:** - Prevent variable name collisions - Working with nested queries or multiple scopes - Building queries programmatically - Use with `select()` for local variable scoping **Example - Preventing Name Collisions:** ```javascript // Without unique variables - potential collision const [x] = WOQL.vars("x"); const [x2] = WOQL.vars("x"); // Same name! Could cause issues // With unique variables - guaranteed unique const [a] = WOQL.vars_unique("x"); const [b] = WOQL.vars_unique("x"); // a might be "x_1", b might be "x_2" - no collision ``` **Example - Local Scope with select():** ```javascript const [localResult] = WOQL.vars_unique("result"); const query = WOQL.select([localResult], WOQL.eval(WOQL.times(2, 3), localResult) ); await client.query(query); // Returns: [{ result_23: { "@type": "xsd:decimal", "@value": 6 }}] // The suffix ensures this doesn't conflict with other "result" variables ``` **Example - Resetting Counter for Testing:** ```javascript // Reset counter to predictable value (useful for tests) WOQL.vars_unique_reset_start(0); const [v1] = WOQL.vars_unique("test"); // test_1 const [v2] = WOQL.vars_unique("test"); // test_2 const [v3] = WOQL.vars_unique("test"); // test_3 ``` **Key Characteristics:** - ✅ Automatic name uniqueness - ✅ Perfect for nested scopes - ✅ Prevents accidental variable reuse - ✅ Can reset counter with `vars_unique_reset_start()` - ⚠️ Variable names less predictable - ⚠️ Result keys include suffixes ## Comparison and Decision Guide ### Array vs. Object Access **Choose Array-based (`vars`, `vars_unique`) when:** - Writing simple queries with few variables - You prefer destructuring syntax - Variable count is small and fixed - You want minimal syntax overhead **Choose Object-based (`Vars`, `VarsUnique`) when:** - Working with many variables - Building complex, multi-part queries - You want self-documenting code - Passing variable groups between functions - Organizing variables by domain/entity ### Exact vs. Unique Naming **Choose Exact names (`vars`, `Vars`) when:** - Working on simple, isolated queries - You need predictable result key names - Debugging and you want readable output - No risk of variable name conflicts - Building examples or documentation **Choose Unique names (`vars_unique`, `VarsUnique`) when:** - Working with nested query scopes - Using `select()` for variable isolation - Building reusable query components - Programmatically generating queries - Large codebase with multiple developers - You need guaranteed name uniqueness ## Practical Examples ### Example 1: Simple Data Retrieval ```javascript // Using vars() - simple and direct const [person, name] = WOQL.vars("Person", "Name"); const query = WOQL.select([person, name], WOQL.triple(person, "rdf:type", "@schema:Person"), WOQL.triple(person, "name", name) ); ``` ### Example 2: Complex Query with Many Variables ```javascript // Using Vars() - better organization const v = WOQL.Vars( "person", "name", "email", "phone", "address", "city", "country", "postalCode" ); const query = WOQL.and( WOQL.triple(v.person, "rdf:type", "@schema:Person"), WOQL.triple(v.person, "name", v.name), WOQL.triple(v.person, "email", v.email), WOQL.triple(v.person, "phone", v.phone), WOQL.triple(v.person, "address", v.address), WOQL.triple(v.address, "city", v.city), WOQL.triple(v.address, "country", v.country), WOQL.triple(v.address, "postalCode", v.postalCode) ); ``` ### Example 3: Nested Scopes with select() ```javascript // Using vars_unique() for isolated scopes const [outerPerson] = WOQL.vars("person"); const [innerPerson, details] = WOQL.vars_unique("person", "details"); const query = WOQL.and( WOQL.triple(outerPerson, "rdf:type", "@schema:Person"), WOQL.select([details], WOQL.and( WOQL.eq(innerPerson, outerPerson), WOQL.triple(innerPerson, "details", details) ) ) ); // innerPerson gets unique suffix, preventing confusion ``` ### Example 4: Reusable Query Components ```javascript // Using VarsUnique() for composable queries function createFilterByAge(minAge) { const v = WOQL.VarsUnique("person", "age"); return WOQL.and( WOQL.triple(v.person, "age", v.age), WOQL.greater(v.age, minAge) ); } function createFilterByCity(city) { const v = WOQL.VarsUnique("person", "personCity"); return WOQL.and( WOQL.triple(v.person, "city", v.personCity), WOQL.eq(v.personCity, city) ); } // Compose without conflicts const query = WOQL.and( createFilterByAge(18), createFilterByCity("London") ); // Each function gets unique variable names automatically ``` ### Example 5: Mathematical Operations ```javascript // All four methods work for calculations // vars - simple array const [result1] = WOQL.vars("result"); WOQL.eval(WOQL.times(2, 3), result1); // vars_unique - unique array const [result2] = WOQL.vars_unique("result"); WOQL.eval(WOQL.plus(10, 5), result2); // Vars - object access const v1 = WOQL.Vars("sum", "product"); WOQL.and( WOQL.eval(WOQL.plus(5, 3), v1.sum), WOQL.eval(WOQL.times(5, 3), v1.product) ); // VarsUnique - unique object access const v2 = WOQL.VarsUnique("sum", "product"); WOQL.and( WOQL.eval(WOQL.plus(7, 2), v2.sum), WOQL.eval(WOQL.times(7, 2), v2.product) ); ``` ## Best Practices ### 1. Consistent Naming Conventions Use descriptive variable names: ```javascript // ✅ Good - descriptive const v = WOQL.Vars("employeeName", "employeeEmail", "departmentName"); // ❌ Bad - cryptic const v = WOQL.Vars("x", "y", "z"); ``` ### 2. Group Related Variables ```javascript // ✅ Good - grouped by entity const employee = WOQL.Vars("id", "name", "email"); const department = WOQL.Vars("id", "name", "budget"); // ❌ Bad - mixed together const v = WOQL.Vars("empId", "empName", "deptId", "deptName"); ``` ### 3. Use Unique Variables for Nested Scopes ```javascript // ✅ Good - unique variables prevent conflicts function subQuery() { const v = WOQL.VarsUnique("person", "name"); return WOQL.triple(v.person, "name", v.name); } // ❌ Risky - exact names might conflict across scopes (in larger code bases) function subQuery() { const v = WOQL.Vars("person", "name"); return WOQL.triple(v.person, "name", v.name); } ``` ### 4. Reset Counter in Tests ```javascript // For predictable test results beforeEach(() => { WOQL.vars_unique_reset_start(0); }); test('query with unique variables', () => { const [v1] = WOQL.vars_unique("test"); // Always test_1 expect(v1.name).toBe("test_1"); }); ``` ### 5. Choose Appropriate Method for Query Complexity ```javascript // Simple query and for bindings: use vars() const [person, name] = WOQL.vars("person", "name"); // Medium complexity and for bindings: use Vars() const v = WOQL.Vars("person", "name", "email", "age"); // Complex/reusable: prefer to use VarsUnique() const v = WOQL.VarsUnique("person", "name", "email", "age", "address"); ``` ## Common Patterns ### Pattern 1: Filter and Return Pattern ```javascript const v = WOQL.Vars("employee", "name", "salary"); WOQL.select([v.employee, v.name], WOQL.and( WOQL.triple(v.employee, "name", v.name), WOQL.triple(v.employee, "salary", v.salary), WOQL.greater(v.salary, 50000) ) ); ``` ### Pattern 2: Join Pattern ```javascript const v = WOQL.Vars("employee", "empName", "department", "deptName"); WOQL.and( WOQL.triple(v.employee, "name", v.empName), WOQL.triple(v.employee, "department", v.department), WOQL.triple(v.department, "name", v.deptName) ); ``` ### Pattern 3: Aggregation Pattern ```javascript const v = WOQL.Vars("department", "count"); WOQL.group_by([v.department], [v.count], WOQL.count(v.employee, v.count), WOQL.triple(v.employee, "department", v.department) ); ``` ### Pattern 4: Conditional Logic Pattern ```javascript const v = WOQL.Vars("person", "status", "age"); WOQL.or( WOQL.and( WOQL.triple(v.person, "age", v.age), WOQL.greater(v.age, 65), WOQL.eq(v.status, "senior") ), WOQL.and( WOQL.triple(v.person, "age", v.age), WOQL.less(v.age, 18), WOQL.eq(v.status, "minor") ) ); ``` ## Troubleshooting ### Issue: Variable Name Conflicts **Problem:** Results are mixed up or unexpected ```javascript // Both use "result" - might conflict const [result1] = WOQL.vars("result"); const [result2] = WOQL.vars("result"); ``` **Solution:** Use unique variables ```javascript const [result1] = WOQL.vars_unique("result"); const [result2] = WOQL.vars_unique("result"); // result1 → "result_1", result2 → "result_2" ``` ### Issue: Cannot Access Variable Properties **Problem:** `v.varName is undefined` ```javascript const [v] = WOQL.vars("person", "name"); // Wrong - returns array // v is just "person", not an object ``` **Solution:** Use `Vars()` for object access ```javascript const v = WOQL.Vars("person", "name"); // Correct - returns object // v.person and v.name are accessible ``` **Problem:** `v.varName is undefined with vio:WOQLSyntaxError` ```javascript const v = WOQL.Vars("person_renamed"); // Wrong - code is still using v.person // v.person was used previously, and now getting "Not well formed WOQL JSON-LD" ``` **Solution:** Use care when renaming variables produced by `Vars()`, prefer only using in a local scope ```javascript const v = WOQL.Vars("person", "name"); // Correct - returns object // v.person and v.name are accessible ``` ### Issue: Unpredictable Variable Names in Tests **Problem:** Test results vary between runs ```javascript test('my test', () => { const [v] = WOQL.vars_unique("test"); expect(v.name).toBe("test_1"); // Fails if counter was incremented before }); ``` **Solution:** Reset counter before test ```javascript test('my test', () => { WOQL.vars_unique_reset_start(0); const [v] = WOQL.vars_unique("test"); expect(v.name).toBe("test_1"); // Always passes }); ``` ### Issue: Too Many Variables to Destructure **Problem:** Destructuring line is too long ```javascript const [v1, v2, v3, v4, v5, v6, v7, v8] = WOQL.vars(...); // Hard to read ``` **Solution:** Use object-based approach ```javascript const v = WOQL.Vars("v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8"); // Access as v.v1, v.v2, etc. ``` ## Migration Guide ### From String Variables to vars() ```javascript // Old style - strings WOQL.triple("v:Person", "v:name", "v:Name"); // New style - vars() const [person, name] = WOQL.vars("Person", "Name"); WOQL.triple(person, name, name); ``` ### From vars() to Vars() ```javascript // Before - array destructuring const [person, name, email, age, city] = WOQL.vars(...); // After - object access const v = WOQL.Vars("person", "name", "email", "age", "city"); // Access with v.person, v.name, etc. ``` ### From Vars() to VarsUnique() ```javascript // Before - potential conflicts function createQuery() { const v = WOQL.Vars("person", "name"); return WOQL.triple(v.person, "name", v.name); } // After - guaranteed unique function createQuery() { const v = WOQL.VarsUnique("person", "name"); return WOQL.triple(v.person, "name", v.name); } ``` ## Quick Reference ```javascript // Import const { vars, vars_unique, Vars, VarsUnique } = WOQL; // Array-based with exact names const [a, b] = WOQL.vars("a", "b"); // Array-based with unique names const [x, y] = WOQL.vars_unique("x", "y"); // x_1, y_2 // Object-based with exact names const v = WOQL.Vars("person", "name"); // Access: v.person, v.name // Object-based with unique names const u = WOQL.VarsUnique("person", "name"); // Access: u.person, u.name (but actual names have suffixes) // Reset unique counter (for tests) WOQL.vars_unique_reset_start(0); ``` ## Related Documentation - [JavaScript Client Reference](/docs/javascript/) - Complete JS client API - [WOQL Basics](/docs/woql-basics/) - Introduction to WOQL queries - [Unification of Variables in Datalog](/docs/unification-of-variables-in-datalog/) - Understanding how variables are resolved - [Query Documents with JS](/docs/query-documents/) - Document querying examples - [Run WOQL Query](/docs/run-woql-query/) - Execute queries with the client - [Database Path Identifiers](/docs/database-path-identifiers/) - Understanding DB_SPEC and GRAPH_SPEC ## Summary Choose your variable generation method based on your needs: - **`vars()`** - Simple queries, array destructuring, exact names - **`vars_unique()`** - Simple queries with name safety, local scopes - **`Vars()`** - Complex queries, clean object access, exact names - **`VarsUnique()`** - Complex reusable queries, object access, guaranteed uniqueness Start with `vars()` or `Vars()` for straightforward queries. Switch to `vars_unique()` or `VarsUnique()` when building reusable components, working with nested scopes, or preventing variable name conflicts in large applications. The right choice makes your WOQL queries more readable, maintainable, and bug-free!