DevTools Team
April 25, 2025 (Updated: April 25, 2025)
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.
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.
The most basic feature of JSONata is the ability to navigate through JSON structures using path expressions:
// 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 } ] } }
json
To access the customer's city:
customer.address.city
Result:
"New York"
JSONata makes working with arrays intuitive:
customer.orders.product
Result:
[ "Laptop", "Smartphone" ]
You can use conditions to filter data:
customer.orders[price > 1000].product
Result:
"Laptop"
JSONata includes built-in functions and allows custom functions for data transformation:
$sum(customer.orders.price)
Result:
2000
Easily reshape your data:
{ "customerName": customer.name, "totalSpent": $sum(customer.orders.price), "orderCount": $count(customer.orders) }
Result:
{ "customerName": "John Smith", "totalSpent": 2000, "orderCount": 2 }
json
JSONata is particularly useful in scenarios where you need to:
While you can achieve similar results using JavaScript, JSONata offers several advantages:
jq is another popular JSON processor:
To start using JSONata in your JavaScript or TypeScript project:
npm install jsonata
bash
Basic usage:
const 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);
javascript
When working with APIs that return more data than you need, JSONata can transform responses to match your application's requirements:
const 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})
javascript
JSONata excels at performing calculations on data:
const 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));
javascript
This example shows basic data aggregation: calculating totals, averages, and summing values by category.
Use JSONata to customize configurations based on environments:
const 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));
javascript
JSONata allows you to define custom functions for reusable logic:
const 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); }
javascript
Handle missing or invalid data gracefully:
const 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); }
javascript
Process nested structures with recursive functions:
const 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); }
javascript
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.