# Equals Checks if the value at a key equals a specified value. ## Overview The `equals` condition evaluates whether a field's value exactly matches a specified value. It works with strings, numbers, booleans, arrays, and objects, making it one of the most versatile conditions for exact matching scenarios. ## Use Cases - **Status Matching**: Route based on exact status values - **Boolean Flags**: Check feature flags or boolean fields - **Exact Value Filtering**: Filter for specific numeric or string values - **Object/Array Comparison**: Compare complex nested structures ## Configuration | Setting | Type | Required | Description | | ------------------ | ------- | -------- | -------------------------------------------------------------------------------------------- | | `key` | string | Yes | The field path to check. Supports dot notation for nested fields. Use `*` to check all keys.| | `value` | any | Yes | The value to compare against. Can be string, number, boolean, array, or object. | | `case_insensitive` | boolean | No | If `true`, performs case-insensitive string comparison. | | `not` | boolean | No | If `true`, inverts the condition (matches if values are NOT equal). | ### Value Format Internally, all values are stored as strings. This means `123` matches both the number `123` and the string `"123"` in your data. To match only a specific type, wrap the value in quotes: | Input | Matches | |-------|---------| | `hello` | `"hello"` | | `123` | `123` (number) and `"123"` (string) | | `"123"` | `"123"` (string only, not the number `123`) | | `true` | `true` (boolean) and `"true"` (string) | | `"true"` | `"true"` (string only, not the boolean `true`) | | `["a","b"]` | `["a","b"]` or `["b","a"]` (order-independent) | | `{"k":"v"}` | `{"k":"v"}` | Use quotes when you need to distinguish between a string and its numeric or boolean equivalent. ## Examples ### String Comparison Check for exact string match: ```json { "type_id": "equals", "config": { "key": "status", "value": "active" } } ``` **Matches:** ```json {"status": "active"} ``` **Does not match:** ```json {"status": "Active"} {"status": "active "} {"status": "inactive"} ``` ### Case-Insensitive String Comparison Match strings regardless of case: ```json { "type_id": "equals", "config": { "key": "status", "value": "active", "case_insensitive": true } } ``` **Matches:** ```json {"status": "active"} {"status": "Active"} {"status": "ACTIVE"} ``` ### Numeric Comparison Check for exact numeric value: ```json { "type_id": "equals", "config": { "key": "priority", "value": 1 } } ``` **Matches:** ```json {"priority": 1} {"priority": 1.0} ``` **Does not match:** ```json {"priority": 2} {"priority": "1"} ``` ### Boolean Comparison Check boolean fields: ```json { "type_id": "equals", "config": { "key": "is_active", "value": true } } ``` **Matches:** ```json {"is_active": true} ``` **Does not match:** ```json {"is_active": false} {"is_active": "true"} ``` ### Array Comparison (Unordered) Compare arrays - order does not matter: ```json { "type_id": "equals", "config": { "key": "tags", "value": ["a", "b", "c"] } } ``` **Matches:** ```json {"tags": ["a", "b", "c"]} {"tags": ["c", "a", "b"]} {"tags": ["b", "c", "a"]} ``` **Does not match:** ```json {"tags": ["a", "b"]} {"tags": ["a", "b", "c", "d"]} ``` ### Object Comparison (Unordered) Compare objects - key order does not matter: ```json { "type_id": "equals", "config": { "key": "config", "value": {"enabled": true, "timeout": 30} } } ``` **Matches:** ```json {"config": {"enabled": true, "timeout": 30}} {"config": {"timeout": 30, "enabled": true}} ``` **Does not match:** ```json {"config": {"enabled": true}} {"config": {"enabled": true, "timeout": 30, "extra": "field"}} ``` ### Nested Field Comparison Check values in nested fields: ```json { "type_id": "equals", "config": { "key": "user.role", "value": "admin" } } ``` **Matches:** ```json {"user": {"role": "admin", "name": "John"}} ``` ### Not Equal Check Match records where the value is NOT equal: ```json { "type_id": "equals", "config": { "key": "status", "value": "deleted", "not": true } } ``` **Matches:** ```json {"status": "active"} {"status": "pending"} ``` **Does not match:** ```json {"status": "deleted"} ``` ### Wildcard Key Check Check if any field equals a value: ```json { "type_id": "equals", "config": { "key": "*", "value": "critical" } } ``` **Matches:** ```json {"severity": "critical"} {"priority": "critical"} {"status": "critical"} ``` ## Common Patterns ### Status-Based Routing Route by exact status: ```json { "operator": "and", "conditions": [ {"type_id": "equals", "config": {"key": "type", "value": "order"}}, {"type_id": "equals", "config": {"key": "status", "value": "shipped"}} ] } ``` ### Feature Flag Check Route based on feature flags: ```json { "operator": "and", "conditions": [ {"type_id": "equals", "config": {"key": "features.new_checkout", "value": true}}, {"type_id": "equals", "config": {"key": "features.beta_user", "value": true}} ] } ``` ### Environment Routing Route production vs non-production: ```json { "operator": "and", "conditions": [ {"type_id": "equals", "config": {"key": "environment", "value": "production"}}, {"type_id": "equals", "config": {"key": "region", "value": "us-east-1"}} ] } ``` ### Null Check Check for null values: ```json { "type_id": "equals", "config": { "key": "deleted_at", "value": null } } ``` **Matches:** ```json {"deleted_at": null} ``` **Does not match:** ```json {"deleted_at": "2024-01-15"} {"id": "123"} ``` Note: A missing field is different from a null value. Use `key_exists` to check for missing fields. ### Exclude Specific Values Filter out specific statuses: ```json { "operator": "and", "conditions": [ {"type_id": "equals", "config": {"key": "status", "value": "deleted", "not": true}}, {"type_id": "equals", "config": {"key": "status", "value": "archived", "not": true}} ] } ``` ## Best Practices 1. **Use exact types**: Ensure the value type matches your data (`1` vs `"1"`, `true` vs `"true"`). 2. **Use `case_insensitive` when appropriate**: For user-generated content or when case may vary. 3. **Remember array comparison is unordered**: `["a", "b"]` equals `["b", "a"]`. 4. **Remember object comparison is unordered**: Key order doesn't matter for equality. 5. **Use `equals_any` for multiple values**: If checking against several possible values, `equals_any` is more readable. 6. **Null vs missing**: Use `equals` with `null` to check for null values; use `key_exists` to check for missing fields. ## Type Handling | Data Type | Behavior | |-----------|----------| | Strings | Direct comparison (case-sensitive by default) | | Numbers | Numeric comparison (`1` equals `1.0`) | | Booleans | Direct comparison (`true` vs `false`) | | Arrays | Unordered deep comparison (same elements in any order) | | Objects | Unordered deep comparison (same keys/values, any key order) | | Null | Matches only `null` values (not missing fields) | ## Limitations - Single value comparison (use `equals_any` for multiple values) - `case_insensitive` only applies to string comparisons - Missing fields return `false` (not equal to anything, including `null`) ## Troubleshooting **String not matching:** - Check for exact case (use `case_insensitive: true` if needed) - Look for trailing spaces or hidden characters - Verify encoding (special characters) **Number not matching:** - Ensure value is a number, not a string (`1` vs `"1"`) - Check for floating point precision issues **Boolean not matching:** - Use actual boolean values (`true`/`false`), not strings - Check if your data source serializes booleans as strings **Array not matching:** - Ensure all elements are present - Remember comparison is unordered - Check for duplicate handling (duplicates must match) **Null not matching:** - A missing field is not the same as `null` - Use `key_exists` with `not: true` to check for missing fields