Understanding recursion in JSONata
Next, we'll present an example that defines recursion to navigate and transform a JSON structure. This article will detail the initial example and expand it with additional explanations, practical examples and use cases, providing a comprehensive understanding of the application of recursion in JSONata.
(
$person := function($node) { $node.{"n": Name, "p":$person(Parent.Person)}};
{
"Person": Person ~> $person($)
}
)
Explanation
1. Function Definition:
$person := function($node) { $node.{"n": Name, "p":$person(Parent.Person)}};
The line above defines a recursive function called $person. The function takes a node ($node) as an argument. It returns an object containing:
"n": Name - The Name property of the current node.
"p": $person(Parent.Person) - The result of calling the $person function on the Parent.Person property of the current node, allowing for recursive navigation.
2. Applying the Function
{
"Person": Person ~> $person($)
}
This part applies the $person function to the "Person" field in the current context (denoted by $). The ~> operator pipes the "Person" field through the $person function.
Enhancing the Example
Let's enhance the example by adding more fields for transformation and navigating through more deeply nested JSON structures. Consider the following more complex JSON structure:
JSON Input Example
{
"Person": {
"Name": "João",
"Age": 30,
"Parent": {
"Person": {
"Name": "Maria",
"Age": 55,
"Parent": {
"Person": {
"Name": "Roberto",
"Age": 80
}
}
}
}
}
}
Expanded Function and Query
Let's modify the function to include the "Age" property and handle cases where "Parent" may be absent.
(
$person := function($node) {
$node.{
"n": Name,
"a": Age,
"p": $exists($person(Parent.Person)) ? $person(Parent.Person) : null
}
};
{
"Person": Person ~> $person($)
}
)
Explanation
The modified function now includes "a": Age to capture each person's age.
The ternary operator ($exists($person(Parent.Person)) ? ... : null) ensures the function returns "null" if the node is not present, preventing errors when navigating the hierarchy.
Example Output
Applying the expanded query to the input JSON example will result in:
{
"Person": {
"n": "João",
"a": 30,
"p": {
"n": "Maria",
"a": 55,
"p": {
"n": "Roberto",
"a": 80,
"p": null
}
}
}
}
Additional Example & Use Cases
Example with Siblings
Let's consider an example where each person can have siblings.
JSON Input
{
"Person": {
"Name": "João",
"Age": 30,
"Siblings": [
{
"Name": "Ana",
"Age": 25
},
{
"Name": "Alex",
"Age": 28
}
],
"Parent": {
"Person": {
"Name": "Maria",
"Age": 55,
"Parent": {
"Person": {
"Name": "Roberto",
"Age": 80
}
}
}
}
}
}
Expanded Function and Query to Handle Siblings
We can expand our role even further to include brothers:
(
$person := function($node) {
$node.{
"n": Name,
"a": Age,
"s": $exists($person(Siblings)) ? $person(Siblings) : null,
"p": $exists($person(Parent.Person)) ? $person(Parent.Person) : null
}
};
{
"Person": Person ~> $person($)
}
)
Explanation
The line "s": $exists($person(Siblings)) ? $person(Siblings) : null maps the Siblings array and transforms each sibling into an object.
Example Output
Applying the expanded query to the input JSON example will result in:
{
"Person": {
"n": "João",
"a": 30,
"s": [
{
"n": "Ana",
"a": 25,
"s": null,
"p": null
},
{
"n": "Alex",
"a": 28,
"s": null,
"p": null
}
],
"p": {
"n": "Maria",
"a": 55,
"s": null,
"p": {
"n": "Roberto",
"a": 80,
"s": null,
"p": null
}
}
}
}
Conclusion
The recursive function in JSONata provides a powerful way to navigate and transform nested JSON structures. By defining and applying such functions, you can traverse hierarchical data, handle optional fields and even map arrays to produce complex, automated transformations.
Last updated