How can we help?

Advanced data transformations using JSON path queries (JMESPath)

Tal Bereznitskey
Tal Bereznitskey
  • Updated

Advanced mapping using JMESPath syntax

JMESPath helps you pick and transform values inside JSON. (It’s a query language, meaning it lets you “ask” JSON for exactly the value you want.) In Torii, you can use it to extract values from nested objects, work with lists, and format the final value that gets mapped into a field.

To learn the syntax and try examples, use the official JMESPath playground: https://jmespath.org/

One simple way to use it: write your JMESPath query on the top, paste your JSON below it, and see the result instantly.


The following guide walks you step by step from the basics to advanced concepts.

 

1) Basics: paths and indexing

Simple JMESPath expressions look like dot notation paths, for example: app.name.

Example: Get a field

Input

{
  "app": {
    "id": 1,
    "name": "Torii"
  }
}

JMESPath query

app.name

Result

"Torii"

// Note how a string always starts and ends with the " character

Example: Get a value by list index

Input

{ "apps": [ { "name": "Torii" }, { "name": "AWS" } ] }

JMESPath query

apps[0].name

Result

"Torii"

// This is also a string which starts and ends with the " character

2) Lists: [] means “do this for every item”

apps[].name means “for every item in the apps list (array), return its name”.

Example: Get all names

Input

{
  "apps": [
    { "id": 1, "name": "Torii" },
    { "id": 2, "name": "AWS" }
  ]
}

JMESPath query

apps[].name

Result

["Torii", "AWS"]

// Note how an array always starts and ends with [] characters

3) Turn a list into text: join

join glues list items together using a separator (like a comma) into a string.

Example: Join app names with a comma

Input

{ "apps": [ { "name": "Torii" }, { "name": "AWS" } ] }

JMESPath query

join(',', apps[].name)

Result

"Torii,AWS"

// Note how the result is a string ("") and not an array ([])

4) Pipes and the current value: | and @

  • | means: take the result and pass it to the next function.
  • @ means: “the current value” (think: “whatever we have so far”).

Example: Join app names using | and @

Input

{ "apps": [ { "name": "Torii" }, { "name": "AWS" } ] }

JMESPath query

apps[].name | join(',', @)

Result

"Torii,AWS"

This works in two steps:

  1. apps[].name produces the array ["Torii", "AWS"]
  2. join(',', @) joins the current value into a string

5) Functions that run “per item”: map and &

Sometimes you need to apply the same function to every item in a list.

  • map(expression, list) returns a new list after applying expression to each item.
  • & is used to write an expression that will be applied to each item. Inside that expression, you usually use @ to refer to the current item.

Example: Convert every id to text

Input

{ "apps": [ { "id": 1 }, { "id": 2 } ] }

JMESPath query

map(&to_string(@), apps[].id)

Result

["1", "2"]

When to use map(...) vs []

  • Use [] when you’re picking fields from each item, like apps[].id or apps[].name.
  • Use map(...) when you need to run a function per item, especially when you need & and @, like converting each item: map(&to_string(@), apps[].id).

A quick way to remember it:

  • [] selects values
  • map(...) transforms each value

6) Converting formats: to_string and to_number

Some functions only work if the value is in the right format, like text vs number.

  • join(...) expects a list of strings
  • math functions like sum(...) expect numbers

Example: Get all ids as one comma-separated string

Input

{ "apps": [ { "id": 1 }, { "id": 2 } ] }

JMESPath query

apps[].id | map(&to_string(@), @) | join(',', @)

Result

"1,2"

Example: Convert strings that look like numbers into numbers

Input

{ "costs": ["10", "20", "3"] }

JMESPath query

map(&to_number(@), costs)

Result

[10, 20, 3]

7) Filtering: keep only the items you want

Filtering means: keep only the items that match a condition.

Example: Keep only the AWS app

Input

{
  "apps": [
    {
      "id": 1,
      "name": "Torii"
    },
    {
      "id": 2,
      "name": "AWS"
    }
  ]
}

JMESPath query

apps[?name == 'AWS']

Result

[
  {
    "id": 2,
    "name": "AWS"
  }
]

8) Bigger example: filter, pick nested values, and format output

Example: Filter list and join user names

This will:

  1. keep only the AWS app
  2. take its users list and turn it into one combined list ([])
  3. join the list into one string using " and "

Input

{
  "apps": [
    {
      "name": "Torii",
      "users": ["Joe", "Daniel"]
    },
    {
      "name": "AWS",
      "users": ["Bob", "Claire"]
    }
  ]
}

JMESPath query

apps[?name == 'AWS'].users[] | join(' and ', @)

Result

"Bob and Claire"

// apps[?name == 'AWS'] --> { "name": "AWS", "users": ["Bob", "Claire"] }
// .users[] --> ["Bob", "Claire"]
// join(' and ', @) --> "Bob and Claire"

9) Add up values: sum

sum(arrayOfNumbers) adds up numbers in an array.

Example: Sum values that come back as strings

Input

{ "lineItems": [ {"price": "19.99"}, {"price": "10"} ] }

JMESPath query

sum(map(&to_number(@), lineItems[].price))

Result

29.99

// lineItems[].price --> ["19.99", "10"]
// map(&to_number(@), ...) --> [19.99, 10]
// sum(...) --> 29.99

Common use cases in Torii mappings

  • Extract a single value: a.b.c
  • Get a list of values: apps[].name
  • Build text from a list: apps[].name | join(', ', @)
  • Filter items by a field: apps[?name == 'AWS']
  • Work with a nested list: apps[].users[]
  • Convert formats when needed: to_string(...), to_number(...)
  • Calculate totals: sum(...)

Using LLM and AI agents to help with JMESPath

ChatGPT, Gemini, Microsoft Co-pilot, Claude and other LLM chatbots are great at formulating JMESPath queries based on your goal. For example, you can use the following prompt:

For the following input JSON:
{
  "apps": [
    {
      "name": "Torii",
      "users": ["Joe", "Daniel"]
    },
    {
      "name": "AWS",
      "users": ["Bob", "Claire"]
    }
  ]
}

Please provide a JMESPath query that will result in the users
of AWS combined to a string, separated by a comma.

Please explain how it works as well.

A response from the LLM may look like:

JMESPath query:

join(', ', apps[?name=='AWS'] | [0].users)


How it works:

apps[?name=='AWS'] filters the apps array down to only the objects whose name is "AWS". Result is an array (typically with one item).

| [0] pipes that filtered array into an index operation, taking the first matching object (the AWS app object).

.users selects its users array, e.g. ["Bob","Claire"].

join(', ', ...) joins that array into a single string with , between entries, producing: "Bob, Claire".

How to test your JMESPath queries

  1. Copy a real JSON example from the Torii step you’re mapping
  2. Paste it into the JMESPath playground (https://jmespath.org/)
  3. Write your query and verify the output
  4. Make sure the final output matches what the target field expects
    1. If you are going to send the result over email or Slack/Teams message, it should be a string or a number.
    2. If you are going to send this value in a subsequent API call, it might need to be an array or object.
    3. In general, these rules apply:
      1. If the target field is text, end with a string (often join(...)).
      2. If it’s a number field, return a number (use to_number(...), and use to_number(...) before sum(...)).
      3. If the field expects a list, return an array like ["a", "b"].

Was this article helpful?

0 out of 0 found this helpful

Have more questions? Submit a request