Query JSON using JSONata
Updated: May 4, 2026
This example shows how to read a JSON document (or any other supported format) and query or transform it using JSONata expressions with DataPipeline.
Input JSON File
[
{
"id": "0001",
"type": "donut",
"name": "Cake",
"ppu": 0.55,
"batters":
{
"batter":
[
{ "id": "1001", "type": "Regular" },
{ "id": "1002", "type": "Chocolate" },
{ "id": "1003", "type": "Blueberry" },
{ "id": "1004", "type": "Devil's Food" }
]
},
"topping":
[
{ "id": "5001", "type": "None" },
{ "id": "5002", "type": "Glazed" },
{ "id": "5005", "type": "Sugar" },
{ "id": "5007", "type": "Powdered Sugar" },
{ "id": "5006", "type": "Chocolate with Sprinkles" },
{ "id": "5003", "type": "Chocolate" },
{ "id": "5004", "type": "Maple" }
]
},
{
"id": "0002",
"type": "donut",
"name": "Raised",
"ppu": 0.55,
"batters":
{
"batter":
[
{ "id": "1001", "type": "Regular" }
]
},
"topping":
[
{ "id": "5001", "type": "None" },
{ "id": "5002", "type": "Glazed" },
{ "id": "5005", "type": "Sugar" },
{ "id": "5003", "type": "Chocolate" },
{ "id": "5004", "type": "Maple" }
]
}
]
Java code listing
package com.northconcepts.datapipeline.examples.jsonata;
import com.northconcepts.datapipeline.core.Record;
import com.northconcepts.datapipeline.core.ValueNode;
import java.io.FileReader;
import static com.northconcepts.datapipeline.jsonata.Jsonata.jsonata;
public class QueryJsonUsingJSONata {
public static void main(String[] args) throws Throwable {
try (FileReader fileReader = new FileReader("data/input/nested-data.json")) {
ValueNode data = Record.fromJson(fileReader);
printSection("Basic Selection");
runQuery("Query 1 - Donut Names", "name", data);
runQuery("Query 2 - Batter Types", "batters.batter.type", data);
printSection("Filtering");
runQuery("Query 3 - Donut Named Raised", "$[name='Raised']", data);
runQuery("Query 4 - Donut with Chocolate with Sprinkles Topping", "$[topping[type='Chocolate with Sprinkles']].name", data);
printSection("Reshaping");
runQuery("Query 5 - Name With Batter And Topping Counts",
"{'name': name, 'batterCount': $count(batters.batter), 'toppingCount': $count(topping)}",
data);
runQuery("Query 6 - Donut Summary",
"{'id': id, 'name': name, 'pricePerUnit': ppu}",
data);
printSection("Metrics");
runQuery("Query 7 - Total Donuts", "$count($)", data);
runQuery("Query 8 - Average Price Per Unit", "$average(ppu)", data);
}
}
private static void runQuery(String title, String expression, ValueNode data) {
System.out.println(title);
System.out.println("Expression: " + expression);
System.out.println("Result: ");
System.out.println(jsonata(expression).evaluate(data));
}
private static void printSection(String title) {
System.out.println("==============================================================");
System.out.println(title);
}
}
Code walkthrough
- Read JSON into memory
Record.fromJson(fileReader)parses the file and returns a ValueNode tree. All queries run against that tree.
- Execute JSONata expressions
runQueryprints the query name, the expression, and the evaluated result fromjsonata(expression).evaluate(data)
- Query patterns used
- Basic Selection: These expressions navigate fields and nested arrays.
- name
- batters.batter.type
- Basic Selection: These expressions navigate fields and nested arrays.
-
- Filtering: These expressions keep only records that match conditions.
- $[name='Raised']
- $[topping[type='Chocolate with Sprinkles']].name
- Filtering: These expressions keep only records that match conditions.
-
- Reshaping: These expressions build new objects with only the fields you want.
- {'name': name, 'batterCount': $count(batters.batter), 'toppingCount': $count(topping)}
- {'id': id, 'name': name, 'pricePerUnit': ppu}
- Reshaping: These expressions build new objects with only the fields you want.
-
- Metrics: These expressions compute aggregate values.
- $count($)
- $average(ppu)
- Metrics: These expressions compute aggregate values.
Console Output
==============================================================
Basic Selection
Query 1 - Donut Names
Expression: name
Result:
[
"Cake",
"Raised"
]
Query 2 - Batter Types
Expression: batters.batter.type
Result:
[
"Regular",
"Chocolate",
"Blueberry",
"Devil's Food",
"Regular"
]
==============================================================
Filtering
Query 3 - Donut Named Raised
Expression: $[name='Raised']
Result:
[
{
"id": "0002",
"type": "donut",
"name": "Raised",
"ppu": 0.55,
"batters": {
"batter": [
{
"id": "1001",
"type": "Regular"
}
]
},
"topping": [
{
"id": "5001",
"type": "None"
},
{
"id": "5002",
"type": "Glazed"
},
{
"id": "5005",
"type": "Sugar"
},
{
"id": "5003",
"type": "Chocolate"
},
{
"id": "5004",
"type": "Maple"
}
]
}
]
Query 4 - Donut with Chocolate with Sprinkles Topping
Expression: $[topping[type='Chocolate with Sprinkles']].name
Result:
"Cake"
==============================================================
Reshaping
Query 5 - Name With Batter And Topping Counts
Expression: {'name': name, 'batterCount': $count(batters.batter), 'toppingCount': $count(topping)}
Result:
[
{
"name": "Cake",
"batterCount": 4,
"toppingCount": 7
},
{
"name": "Raised",
"batterCount": 1,
"toppingCount": 5
}
]
Query 6 - Donut Summary
Expression: {'id': id, 'name': name, 'pricePerUnit': ppu}
Result:
[
{
"id": "0001",
"name": "Cake",
"pricePerUnit": 0.55
},
{
"id": "0002",
"name": "Raised",
"pricePerUnit": 0.55
}
]
==============================================================
Metrics
Query 7 - Total Donuts
Expression: $count($)
Result:
2
Query 8 - Average Price Per Unit
Expression: $average(ppu)
Result:
0.55
