JSONPath Reference
JSONPath is the notation used to navigate and select data within JSON structures. TinySystems uses JSONPath expressions to access data in your flows.
Root Reference
The $ symbol always refers to the root of the data:
// Data
{
"name": "Alice",
"age": 30
}# Expressions
root: {{$}} # The entire object
name: "{{$.name}}" # "Alice"
age: {{$.age}} # 30Property Access
Simple Properties
Access object properties with dot notation:
{
"user": "alice",
"status": "active"
}user: "{{$.user}}" # "alice"
status: "{{$.status}}" # "active"Nested Properties
Chain dots for nested access:
{
"user": {
"profile": {
"name": "Alice",
"email": "alice@example.com"
}
}
}name: "{{$.user.profile.name}}" # "Alice"
email: "{{$.user.profile.email}}" # "alice@example.com"Special Characters
Use bracket notation for properties with special characters:
{
"first-name": "Alice",
"last name": "Smith",
"user.id": "12345"
}first: "{{$['first-name']}}" # "Alice"
last: "{{$['last name']}}" # "Smith"
id: "{{$['user.id']}}" # "12345"Array Access
By Index
Arrays are zero-indexed:
{
"items": ["apple", "banana", "cherry"]
}first: "{{$.items[0]}}" # "apple"
second: "{{$.items[1]}}" # "banana"
third: "{{$.items[2]}}" # "cherry"Negative Indices
Count from the end with negative numbers:
last: "{{$.items[-1]}}" # "cherry"
secondLast: "{{$.items[-2]}}" # "banana"Array of Objects
Access properties within array elements:
{
"users": [
{"name": "Alice", "age": 30},
{"name": "Bob", "age": 25}
]
}firstName: "{{$.users[0].name}}" # "Alice"
firstAge: {{$.users[0].age}} # 30
secondName: "{{$.users[1].name}}" # "Bob"Array Properties
Length
Get the number of elements:
{
"items": [1, 2, 3, 4, 5]
}count: {{$.items.length}} # 5Empty Check
isEmpty: {{$.items.length == 0}}
hasItems: {{$.items.length > 0}}Complex Paths
Deep Nesting
{
"response": {
"data": {
"users": [
{
"profile": {
"contact": {
"email": "user@example.com"
}
}
}
]
}
}
}email: "{{$.response.data.users[0].profile.contact.email}}"Mixed Access
Combine dot and bracket notation:
{
"results": [
{"field-1": "value1"},
{"field-1": "value2"}
]
}first: "{{$.results[0]['field-1']}}" # "value1"
second: "{{$.results[1]['field-1']}}" # "value2"Common Data Patterns
HTTP Request Data
{
"method": "POST",
"path": "/api/users",
"headers": {
"Content-Type": "application/json",
"Authorization": "Bearer token123"
},
"body": {
"name": "Alice",
"email": "alice@example.com"
},
"queryParams": {
"page": "1",
"limit": "10"
}
}method: "{{$.method}}" # "POST"
contentType: "{{$.headers['Content-Type']}}" # "application/json"
auth: "{{$.headers.Authorization}}" # "Bearer token123"
userName: "{{$.body.name}}" # "Alice"
page: "{{$.queryParams.page}}" # "1"Nested Arrays
{
"matrix": [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
}center: {{$.matrix[1][1]}} # 5
topRight: {{$.matrix[0][2]}} # 3Array of Nested Objects
{
"orders": [
{
"id": "ord-1",
"items": [
{"product": "Widget", "qty": 2},
{"product": "Gadget", "qty": 1}
]
}
]
}orderId: "{{$.orders[0].id}}" # "ord-1"
firstProduct: "{{$.orders[0].items[0].product}}" # "Widget"
firstQty: {{$.orders[0].items[0].qty}} # 2Dynamic Access
Variable Keys
Use bracket notation with expressions:
{
"data": {
"name": "Alice",
"age": 30
},
"fieldToRead": "name"
}# Access field dynamically
value: "{{$.data[$.fieldToRead]}}" # "Alice"Computed Indices
{
"items": ["a", "b", "c", "d"],
"index": 2
}item: "{{$.items[$.index]}}" # "c"Edge Cases
Missing Properties
When a property doesn't exist, the expression returns undefined:
{
"user": {
"name": "Alice"
}
}# $.user.email doesn't exist
email: "{{$.user.email}}" # undefined
# Use default value
email: "{{$.user.email || 'not set'}}" # "not set"Null Values
Null is different from undefined:
{
"name": "Alice",
"nickname": null
}nickname: "{{$.nickname}}" # null
hasNickname: {{$.nickname != null}} # false
display: "{{$.nickname || $.name}}" # "Alice"Empty Arrays
{
"items": []
}first: "{{$.items[0]}}" # undefined
count: {{$.items.length}} # 0
hasItems: {{$.items.length > 0}} # falsePath Validation
Check Path Exists
Before accessing deep paths, verify they exist:
# Risk of error if user or profile doesn't exist
name: "{{$.user.profile.name}}"
# Safer with defaults
name: "{{$.user != null ? $.user.profile.name : 'Unknown'}}"
# Or use default at the end
name: "{{$.user.profile.name || 'Unknown'}}"Type Checking
Verify expected types:
# Check if array before accessing
items: "{{Array.isArray($.data) ? $.data : []}}"
# Check if object
value: "{{typeof $.data == 'object' ? $.data.value : null}}"Performance Tips
Direct Access
Prefer direct paths over complex operations:
# ✅ Efficient - direct path
name: "{{$.users[0].name}}"
# ⚠️ Less efficient - operations on arrays
# (when you just need one element)Cache Repeated Access
If you need the same nested value multiple times, consider restructuring your mapping:
# Instead of repeating deep paths
userName: "{{$.response.data.user.profile.name}}"
userEmail: "{{$.response.data.user.profile.email}}"
# Consider mapping the parent object once
# (in components that support it)Next Steps
- Expression Syntax - Complete expression reference
- Operators and Functions - Available operations
- Expression Examples - Practical examples