What Is JSONata? Learn How to Query JSON Like a Pro
JSON (JavaScript Object Notation) has become the standard format for data exchange in modern web applications. As applications grow in complexity, the need for effective ways to query and transform JSON data becomes increasingly important. This is where JSONata comes into play a lightweight, powerful query and transformation language specifically designed for JSON.
What is JSONata?
JSONata is an open-source query and transformation language for JSON data. Created by Andrew Coleman at IBM, it provides a concise and elegant way to extract, transform, and combine data from JSON documents. Think of it as "XPath for JSON" - a purpose-built language that makes complex JSON operations simple.
Key Features of JSONata
1. Path Navigation
The most basic feature of JSONata is the ability to navigate through JSON structures using path expressions:
JSON// Sample JSON data { "customer": { "name": "John Smith", "address": { "city": "New York", "zipCode": "10001" }, "orders": [ { "id": "1001", "product": "Laptop", "price": 1200 }, { "id": "1002", "product": "Smartphone", "price": 800 } ] } }
To access the customer's city:
customer.address.city
Result: "New York"

Path Navigation in JSONata
2. Array Processing
JSONata makes working with arrays intuitive:
customer.orders.product
Result: [ "Laptop", "Smartphone" ]

Array Processing in JSONata
3. Filtering and Conditions
You can use conditions to filter data:
customer.orders[price > 1000].product
Result: "Laptop"

Filtering and Conditions in JSONata
4. Functions and Transformations
JSONata includes built-in functions and allows custom functions for data transformation:
$sum(customer.orders.price)
Result: 2000

Functions and Transformations in JSONata
5. Data Restructuring
Easily reshape your data:
{
"customerName": customer.name,
"totalSpent": $sum(customer.orders.price),
"orderCount": $count(customer.orders)
}
Result:
JSON{ "customerName": "John Smith", "totalSpent": 2000, "orderCount": 2 }

Data Restructuring in JSONata
When to Use JSONata
JSONata is particularly useful in scenarios where you need to:
- Extract specific data from complex JSON documents
- Transform JSON data from one structure to another
- Calculate aggregate values from JSON data
- Filter and sort JSON arrays
- Implement business logic in data processing pipelines
JSONata vs. Other Approaches
JSONata vs. JavaScript
While you can achieve similar results using JavaScript, JSONata offers several advantages:
- Conciseness: JSONata expressions are typically much shorter than equivalent JavaScript code
- Declarative style: Focus on what you want, not how to get it
- Safety: No risk of code injection or side effects
- Optimization: JSONata expressions can be optimized for performance
JSONata vs. jq
jq is another popular JSON processor:
- Integration: JSONata is designed to be embedded in JavaScript applications
- Learning curve: JSONata's syntax is often more intuitive for JavaScript developers
- Functionality: Both are powerful, but with different design philosophies
Getting Started with JSONata
To start using JSONata in your JavaScript or TypeScript project:
npm install jsonata
Basic usage:
JavaScriptconst data = { customer: { name: "John Doe", orders: [ { id: 1, item: "Laptop", price: 1200 }, { id: 2, item: "Phone", price: 800 }, { id: 3, item: "Tablet", price: 1500 } ] } }; const expression = jsonata('customer.orders[price > 1000]'); const result = await expression.evaluate(data); console.log(result);

Basic Usage of JSONata
Use Cases for JSONata
1. API Response Transformation
When working with APIs that return more data than you need, JSONata can transform responses to match your application's requirements:
JavaScriptconst apiResponse = { "records": [ { "id": 1, "firstName": "John", "lastName": "Doe", "age": 28, "email": "john@example.com" }, { "id": 2, "firstName": "Jane", "lastName": "Smith", "age": 32, "email": "jane@example.com" } ], "pagination": { "total": 200, "page": 1, "perPage": 2 } }; // JSONata transformation const expression = jsonata(`{ "users": records.{ "fullName": firstName & " " & lastName, "contactInfo": { "email": email, "age": age } }, "totalUsers": pagination.total }`); const result = await expression.evaluate(apiResponse); console.dir(result,{depth:null})

API Response Transformation with JSONata
2. Data Aggregation and Analysis
JSONata excels at performing calculations on data:
JavaScriptconst salesData = { "transactions": [ { "category": "Electronics", "amount": 1200 }, { "category": "Clothing", "amount": 90 }, { "category": "Electronics", "amount": 500 }, { "category": "Groceries", "amount": 125 } ] }; // Simple aggregation example const expression = jsonata(`{ "total": $sum(transactions.amount), "average": $round($average(transactions.amount), 2), "categories": { "Electronics": $sum(transactions[category="Electronics"].amount), "Clothing": $sum(transactions[category="Clothing"].amount), "Groceries": $sum(transactions[category="Groceries"].amount) } }`); expression.evaluate(salesData) .then(result => console.log(JSON.stringify(result, null, 2))) .catch(err => console.error('Error:', err));
This example shows basic data aggregation: calculating totals, averages, and summing values by category.

Data Aggregation and Analysis with JSONata
3. Configuration Management
Use JSONata to customize configurations based on environments:
JavaScriptconst baseConfig = { "app": { "name": "DevTools App", "environments": { "development": { "apiUrl": "http://localhost:3000/api", "debug": true }, "staging": { "apiUrl": "https://staging-api.example.com", "debug": true }, "production": { "apiUrl": "https://api.example.com", "debug": false } }, "defaults": { "timeout": 5000, "retries": 3 } } }; async function getConfig(env) { const expression = jsonata(`{ "name": app.name, "apiUrl": app.environments.${env}.apiUrl, "debug": app.environments.${env}.debug, "timeout": app.defaults.timeout, "retries": app.defaults.retries }`); const result = await expression.evaluate(baseConfig); return result; } getConfig('development').then(result => console.log(result)).catch(error => console.error(error)); getConfig('staging').then(result => console.log(result)).catch(error => console.error(error)); getConfig('production').then(result => console.log(result)).catch(error => console.error(error));

Configuration Management with JSONata
Advanced JSONata Features
1. Custom Functions
JSONata allows you to define custom functions for reusable logic:
JavaScriptconst apiResponse = { "order": { "items": [ {"name": "Apple","price": 0.99,"quantity": 3}, {"name": "Banana","price": 0.59,"quantity": 5}, {"name": "Orange","price": 1.29,"quantity": 2} ] } } const expression = jsonata(`( $formatCurrency := function($amount) { "$" & $string($round($amount, 2)) }; { "items": order.items.{ "product": name, "price": $formatCurrency(price), "total": $formatCurrency(price * quantity) }, "orderTotal": $formatCurrency($sum(order.items.(price * quantity))) } )`); try { const result = await expression.evaluate(apiResponse); console.dir(result, { depth: null, colors: true }); } catch (err) { console.error('JSONata evaluation failed:\n', err); }

Custom Functions in JSONata
2. Error Handling
Handle missing or invalid data gracefully:
JavaScriptconst apiResponse = { customer: { address: {} } }; const expression = jsonata( `customer.address.zipCode ? customer.address.zipCode : "No ZIP code provided"` ); try { const result = await expression.evaluate(apiResponse); console.dir(result, { depth: null, colors: true }); } catch (err) { console.error('JSONata evaluation failed:\n', err); }

Error Handling in JSONata
3. Recursive Processing
Process nested structures with recursive functions:
JavaScriptconst apiResponse = { "rootNode": { "name": "root", "type": "folder", "children": [ {"name": "file1.txt","type": "file","size": 123}, {"name": "subfolder","type": "folder", "children": [{"name": "file2.txt","type": "file","size": 456}] } ] } }; const expression = jsonata(`( $processNode := function($node) { $node.type = "folder" ? { "name": $node.name, "type": "folder", "children": $node.children.$processNode($) } : { "name": $node.name, "type": "file", "size": $node.size } }; $processNode(rootNode) )`); try { const result = await expression.evaluate(apiResponse); console.dir(result, { depth: null, colors: true }); } catch (err) { console.error('JSONata evaluation failed:\n', err); }

Recursive Processing in JSONata
Conclusion
JSONata offers a powerful yet elegant approach to querying and transforming JSON data. Its concise syntax, combined with rich functionality, makes it an excellent choice for handling JSON in modern applications. Whether you're processing API responses, transforming data structures, or implementing complex business logic, JSONata can significantly simplify your code while making it more maintainable.
For developers working with JSON data, adding JSONata to your toolkit is definitely worth the small investment in learning its syntax. The productivity gains and code clarity it provides will pay dividends as your applications grow in complexity.