Numbers

Functions for working with numbers

Introduction

Numerical data is very common and many of the functions for working with it are standard mathematical operations. This makes working with numbers a natural introduction to JMESPath.

What will I learn?

After following this guide, you'll be able to:

  • Perform mathematical operations on numerical data.
  • Find basic descriptive statistics of the data.
  • Apply mathematical functions and formulas to the data.

Prerequisites

You'll need access to a Documotor tenant and a basic understanding of the platform. Also, you should be familiar with JSON data types and JMESPath expressions.

Sample data

We'll use the following JSON document to demonstrate the basic ways of working with numbers in JMESPath. You'll be able to copy it directly into your Documotor template and play around with it, or find the file and the transformations in the starter pack that you received with your tenant.

{
  "students": [
    { "name": "Alice", "scores": [95, 88, 92, 78, 85] },
    { "name": "Bob", "scores": [87, 91, 89, 82, 96] },
    { "name": "Charlie", "scores": [78, 82, 86, 90, 75] }
  ]
}

As always, it's good practice to analyze the format of the data before starting. All the data is under the students key; its value is an array of objects consisting of the properties name and scores, an array representing the exam scores of a student.

Transformations

Let's format the output object similarly to the input object, as an array studentStats with objects containing the name of the students and some statistics describing their performance. We'll use a combination of a wildcard expression and a multiselect hash of format students[*].{stat: statExpression} to achieve this. Here is an overview of the most common numerical functions:

{
  // Aggregate the statistics into one object per student.
  studentStats: students[*].{
		
    // The wildcard operator changes the current scope.
    // We are now inside the elements of the students array.
    name: name,
		
    bestScore: max(scores),
		
    worstScore: min(scores),

    // Manually calculate the average.
    avgScoreManual: divide(sum(scores), length(scores)),
		
    // Average using the built in function.
    avgScore: avg(scores),

    // ceil, for ceiling, is the rounding-up function (floor rounds down).
    avgScoreRoundedUp: ceil($.avgScore),

    // Find the difference between rounded-up and non-rounded average.
    difference: subtract($.avgScoreRoundedUp, $.avgScoreManual),
    
    // Sort by score and then exclude the first and the last element by slicing.
    avgWithoutBestAndWorst: avg(sort(scores)[1:-1]),

    // Multiply each of the scores by 10 to avoid decimals.
    scoresOutOf1000: map(multiply(@, `10`), scores),
		
    // calculate function has many subfunctions and a special syntax.
    avgScoreRounded: calculate('round(average)', {average: avg(scores)}),
		
    // The calculate function takes in a string formula, 
    // but it does accept an unlimited amount of arguments separated by a comma,
    // so we convert the scores array to string, and then slice out the brackets.
    medianScore: calculate(
      join('', 
        ['median(',
        substring(to_string(scores), `1`, 
        subtract(length(to_string(scores)), `2`)), ')']
      ), 
    `null`)
    }
}

Result

Here is the result of this transformation:

{
  "studentStats": [
    {
      "name": "Alice",
      "bestScore": 95.2,
      "worstScore": 78.9,
      "avgScoreManual": 88.02,
      "avgScore": 88.02000000000001,
      "avgScoreRoundedUp": 89,
      "difference": 0.98,
      "avgWithoutBestAndWorst": 88.66666666666667,
      "scoresOutOf1000": [952, 883, 927, 789, 850],
      "avgScoreRounded": 88.0,
      "medianScore": 88.3
    },
    {
      "name": "Bob",
      "bestScore": 96.5,
      "worstScore": 82.3,
      "avgScoreManual": 89.56,
      "avgScore": 89.56,
      "avgScoreRoundedUp": 90,
      "difference": 0.44,
      "avgWithoutBestAndWorst": 89.66666666666667,
      "scoresOutOf1000": [878, 918, 894, 823, 965],
      "avgScoreRounded": 90.0,
      "medianScore": 89.4
    },
    {
      "name": "Charlie",
      "bestScore": 90.4,
      "worstScore": 75.6,
      "avgScoreManual": 82.56,
      "avgScore": 82.56000000000002,
      "avgScoreRoundedUp": 83,
      "difference": 0.44,
      "avgWithoutBestAndWorst": 82.26666666666667,
      "scoresOutOf1000": [787, 821, 860, 904, 756],
      "avgScoreRounded": 83.0,
      "medianScore": 82.1
    }
  ]
}

Learn more

  • For the full documentation of the calculate, please refer to the function reference page. The function has a special syntax where it accepts strings of mathematical formulas composed of mathematical functions, so the full list of supported functions is explained there.
  • Check out the reference page for Numerical functions for a full overview of numerical functions.