Usage Guide¶
Common patterns and examples for jsonatapy.
Basic Queries¶
Simple Path Access¶
import jsonatapy
data = {
"user": {
"name": "Alice",
"email": "alice@example.com"
}
}
# Single field
result = jsonatapy.evaluate("user.name", data)
# "Alice"
# Nested field
result = jsonatapy.evaluate("user.email", data)
# "alice@example.com"
Array Access¶
data = {
"items": ["apple", "banana", "orange"]
}
# Single element
result = jsonatapy.evaluate("items[0]", data)
# "apple"
# Array slicing
result = jsonatapy.evaluate("items[1..2]", data)
# ["banana", "orange"]
Filtering and Mapping¶
Array Filtering¶
data = {
"products": [
{"name": "Laptop", "price": 1200},
{"name": "Mouse", "price": 25},
{"name": "Keyboard", "price": 75}
]
}
# Filter by condition
result = jsonatapy.evaluate("products[price > 50]", data)
# [{"name": "Laptop", "price": 1200}, {"name": "Keyboard", "price": 75}]
# Extract specific field
result = jsonatapy.evaluate("products[price > 50].name", data)
# ["Laptop", "Keyboard"]
Array Mapping¶
# Transform array elements
result = jsonatapy.evaluate(
'products.{"item": name, "cost": price}',
data
)
# [{"item": "Laptop", "cost": 1200}, ...]
Aggregation¶
data = {
"orders": [
{"quantity": 2, "price": 10},
{"quantity": 3, "price": 15},
{"quantity": 1, "price": 20}
]
}
# Sum
total = jsonatapy.evaluate("$sum(orders.(quantity * price))", data)
# 85
# Count
count = jsonatapy.evaluate("$count(orders)", data)
# 3
# Average
avg = jsonatapy.evaluate("$average(orders.price)", data)
# 15
# Min/Max
min_price = jsonatapy.evaluate("$min(orders.price)", data)
max_price = jsonatapy.evaluate("$max(orders.price)", data)
String Operations¶
data = {"name": "alice"}
# Uppercase
result = jsonatapy.evaluate("$uppercase(name)", data)
# "ALICE"
# Lowercase
result = jsonatapy.evaluate("$lowercase(name)", data)
# "alice"
# Concatenation
result = jsonatapy.evaluate('"Hello, " & name', data)
# "Hello, alice"
# Substring
result = jsonatapy.evaluate('$substring("hello", 1, 4)', {})
# "ell"
# Contains
result = jsonatapy.evaluate('$contains("hello", "ell")', {})
# true
Conditional Expressions¶
data = {"price": 150}
# Ternary operator
result = jsonatapy.evaluate(
'price > 100 ? "expensive" : "affordable"',
data
)
# "expensive"
# Conditional field
result = jsonatapy.evaluate(
'{"price": price, "category": price > 100 ? "premium" : "standard"}',
data
)
# {"price": 150, "category": "premium"}
Object Construction¶
data = {
"firstName": "Alice",
"lastName": "Smith",
"age": 30
}
# Build new object
result = jsonatapy.evaluate(
'{"fullName": firstName & " " & lastName, "age": age}',
data
)
# {"fullName": "Alice Smith", "age": 30}
Using Bindings¶
# Define variables
expr = jsonatapy.compile("items[price > $threshold].name")
result = expr.evaluate(
{"items": [{"name": "A", "price": 100}, {"name": "B", "price": 50}]},
{"threshold": 75}
)
# ["A"]
Compiled Expressions¶
For repeated evaluations, compile once:
expr = jsonatapy.compile("products[category=$cat].name")
# Evaluate with different data
data1 = {
"products": [
{"name": "Item1", "category": "electronics"},
{"name": "Item2", "category": "books"}
]
}
result1 = expr.evaluate(data1, {"cat": "electronics"})
# ["Item1"]
result2 = expr.evaluate(data1, {"cat": "books"})
# ["Item2"]
Higher-Order Functions¶
Map¶
data = {"numbers": [1, 2, 3, 4, 5]}
result = jsonatapy.evaluate(
"$map(numbers, function($n) { $n * 2 })",
data
)
# [2, 4, 6, 8, 10]
Filter¶
Reduce¶
Error Handling¶
def safe_evaluate(expression, data):
try:
return jsonatapy.evaluate(expression, data)
except ValueError as e:
print(f"Error: {e}")
return None
result = safe_evaluate("invalid[[syntax", {})
# Prints: Error: Parse error...
# Returns: None
Guardrails¶
jsonatapy accepts three optional keyword arguments, on compile()/JsonataExpression.compile()
(as defaults) and on every evaluate*() call (as a per-call override), to protect against
runaway or adversarial expressions. All three default to None (unlimited), matching prior
behavior exactly when unspecified.
timeout— maximum evaluation time in milliseconds. RaisesValueErrorwith aD1012code.max_stack_depth— maximum recursion depth (e.g. deeply recursive lambdas). RaisesValueErrorwith aD1011code.max_sequence_length— maximum length of a query-result sequence ($map/$filter/wildcards/ descendants/etc). RaisesValueErrorwith aD2015code.
import jsonatapy
# Set defaults at compile time...
expr = jsonatapy.compile("$sum(items.price)", timeout=1000, max_sequence_length=100_000)
# ...or override per call
result = expr.evaluate(data, timeout=5000)
# A non-terminating expression is stopped instead of hanging forever
try:
jsonatapy.evaluate(
"($inf := function(){$inf()}; $inf())",
None,
timeout=100,
)
except ValueError as e:
print(e)
# D1012: Evaluation timeout after 100 milliseconds. Check for infinite loop
See Error Handling for the full list of guardrail error codes.
Performance Optimization¶
Lazy Conversion by Default (2.2.4+)¶
evaluate(dict) converts Python data lazily: only the fields your expression actually touches
are converted, so simple filters and aggregations over large arrays are several times faster with
no code changes. JsonataData remains the fastest option when you evaluate the same data
repeatedly — its conversion happens once and is reused across every query, while a plain
evaluate(dict) call still converts touched fields on each call.
Result aliasing: parts of a result that come from untouched input subtrees now reference the
original Python objects (matches jsonata-js) rather than copies — mutating the result can
mutate the input. Use copy.deepcopy(result) first if you need an independent copy.
Compile Once¶
# Slow - compiles every time
for data in dataset:
result = jsonatapy.evaluate("items[price > 100]", data)
# Fast - compile once
expr = jsonatapy.compile("items[price > 100]")
for data in dataset:
result = expr.evaluate(data)
JSON String API¶
For large datasets:
import json
expr = jsonatapy.compile("items[price > 100]")
# Large data
data = {"items": [...]} # 1000+ items
# Fast path
json_str = json.dumps(data)
result_str = expr.evaluate_json(json_str)
result = json.loads(result_str)
Real-World Examples¶
API Response Transformation¶
api_response = {
"data": {
"user": {
"id": 123,
"firstName": "Alice",
"lastName": "Smith",
"orders": [
{"id": 1, "total": 100},
{"id": 2, "total": 200}
]
}
}
}
expr = jsonatapy.compile('''
{
"userId": data.user.id,
"fullName": data.user.firstName & " " & data.user.lastName,
"totalSpent": $sum(data.user.orders.total)
}
''')
result = expr.evaluate(api_response)
# {"userId": 123, "fullName": "Alice Smith", "totalSpent": 300}
Data Filtering and Grouping¶
transactions = {
"transactions": [
{"region": "North", "amount": 100},
{"region": "South", "amount": 150},
{"region": "North", "amount": 200}
]
}
# Sum by region
result = jsonatapy.evaluate(
"$sum(transactions[region='North'].amount)",
transactions
)
# 300
ETL Pipeline¶
raw_data = {
"records": [
{"name": "alice", "status": "active", "amount": 100},
{"name": "bob", "status": "inactive", "amount": 200},
{"name": "charlie", "status": "active", "amount": 150}
]
}
transform = jsonatapy.compile('''
records[status="active"].{
"name": $uppercase(name),
"value": amount * 1.1
}
''')
result = transform.evaluate(raw_data)
# [{"name": "ALICE", "value": 110}, {"name": "CHARLIE", "value": 165}]