jq pipelines + Excel formula helpers -- the expression language for computed fields in Boxel
See also BFM v3 Syntax Guide -- the document format that uses JQXL for formulas, inline transforms, and table queries.
field paths jq builtins Excel formulas operators variables strings
Core Mental Model
If you know spreadsheets, you know the core idea. The difference: instead of cell references like A1:B10, you work with JSON -- fields, arrays, and objects.
Spreadsheet
JQXL
Cell value
JSON scalar (number, string, boolean)
Range A1:A10
JSON array [1, 2, 3, ...]
Table with headers
Array of objects [{name, age}, ...]
Current row
. (the dot -- current JSON value)
=A1 + B1
.price + .tax
=SUM(A1:A10)
SUM(.items | map(.amount))
=IFERROR(A1, 0)
IFERROR(.value; 0)
Arguments use semicolons; not commas -- this is jq syntax. ROUND(.x; 2) not ROUND(.x, 2).
Array literals use commas: [1, 2, 3]. If a function call with semicolons is nested inside [...], bind it first: LEFT(.x; 1) as $v | SWITCH([$v, "A", "Alpha"]).
Core Dot Paths & Navigation
Basic Access
ExpressionResult
.
The entire current value (like "this row")
.name
Value of the name field
.patient.name
Nested field access
.orders[0]
First element of the orders array
.orders[-1]
Last element
.orders[2:5]
Slice: elements at index 2, 3, 4
Safe Access & Fallbacks
ExpressionMeaning
.owner?.email
Optional access -- no error if owner is null
.owner?.email//"none"
Alternative operator -- fallback if null/missing
.items[]
Iterate: emit each element as a separate value
..
Recursive descent -- all values at every depth
Core Pipes & Transforms
The pipe | chains operations left-to-right. Each step feeds its output to the next.
Tip: When in doubt, bind it. $subtotal is clearer than repeating the pipeline three times, and safer than threading it through pipes that might break when edited later.
Core Control Flow
Pattern
Syntax
Conditional
if .x > 0 then "positive" elif .x == 0 then "zero" else "negative" end
Try/catch
try (.x / .y) catch "division error"
Reduce
reduce .items[] as $i (0; . + $i.amount)
Foreach
foreach .items[] as $i (0; . + $i.amount)
Define function
def double: . * 2; .values | map(double)
Label/break
label $out | foreach .[] as $x (0; .+$x; if .>100 then ., break $out else . end)
Formula Math & Rounding
Function
Description
Example
ROUND(n; d)
Round to d decimal places
ROUND(3.14159; 2) → 3.14
ROUNDUP(n; d)
Round away from zero
ROUNDUP(3.141; 2) → 3.15
ROUNDDOWN(n; d)
Round toward zero
ROUNDDOWN(3.149; 2) → 3.14
ABS(n)
Absolute value
ABS(-42) → 42
CEILING(n; s)
Round up to significance (alias: CEILING_MATH)
CEILING(2.3; 1) → 3
FLOOR(n; s)
Round down to significance (alias: FLOOR_MATH)
FLOOR(2.7; 1) → 2
INT(n)
Floor to integer
INT(3.9) → 3
MOD(a; b)
Modulo (always non-negative)
MOD(10; 3) → 1
POWER(n; p)
Exponentiation
POWER(2; 10) → 1024
SQRT(n)
Square root
SQRT(144) → 12
PRODUCT(arr)
Product of all numbers
PRODUCT([2, 3, 4]) → 24
PI
Constant 3.14159...
PI → 3.14159...
SIGN(n)
Returns -1, 0, or 1
SIGN(-42) → -1
EVEN(n)
Round up to nearest even
EVEN(3) → 4
ODD(n)
Round up to nearest odd
ODD(4) → 5
GCD(arr)
Greatest common divisor
GCD([12, 8, 20]) → 4
LCM(arr)
Least common multiple
LCM([4, 6, 10]) → 60
FACT(n)
Factorial
FACT(5) → 120
FACTDOUBLE(n)
Double factorial
FACTDOUBLE(7) → 105
COMBIN(n; k)
Combinations
COMBIN(10; 3) → 120
COMBINA(n; k)
Combinations with repetition
COMBINA(4; 2) → 10
PERMUT(n; k)
Permutations
PERMUT(10; 3) → 720
MROUND(n; m)
Round to nearest multiple
MROUND(7.5; 3) → 9
QUOTIENT(n; d)
Integer division
QUOTIENT(7; 2) → 3
DEGREES(rad)
Radians to degrees
DEGREES(PI) → 180
RADIANS(deg)
Degrees to radians
RADIANS(180) → 3.14159...
RAND
Random number 0--1
RAND → 0.7291...
RANDBETWEEN(lo; hi)
Random integer in range
RANDBETWEEN(1; 100)
SUMPRODUCT(arrays)
Sum of element-wise products
SUMPRODUCT([[1,2],[3,4]]) → 11
SUMSQ(arr)
Sum of squares
SUMSQ([3, 4]) → 25
Formula Statistics
Function
Description
Example
SUM(arr)
Sum of numbers (skips nulls)
SUM([10, 20, 30]) → 60
AVERAGE(arr)
Mean (skips nulls)
AVERAGE([10, 20, 30]) → 20
COUNT(arr)
Count of finite numbers
COUNT([1, "a", 3]) → 2
COUNTA(arr)
Count of non-blank values
COUNTA([1, "a", null]) → 2
MAX(arr)
Maximum
MAX([3, 1, 4]) → 4
MIN(arr)
Minimum
MIN([3, 1, 4]) → 1
STDEV(arr)
Sample standard deviation (alias: STDEV_S)
STDEV([2, 4, 4, 4, 5, 5, 7, 9])
STDEV_P(arr)
Population standard deviation
STDEV_P([2, 4, 4, 4, 5, 5, 7, 9])
MEDIAN(arr)
Middle value
MEDIAN([1, 3, 5, 7]) → 4
VAR(arr)
Sample variance (alias: VAR_S)
VAR([2, 4, 4, 4, 5, 5, 7, 9])
VAR_P(arr)
Population variance
VAR_P([2, 4, 4, 4, 5, 5, 7, 9])
LARGE(arr; k)
Kth largest
LARGE([3, 1, 4, 1, 5]; 2) → 4
SMALL(arr; k)
Kth smallest
SMALL([3, 1, 4, 1, 5]; 2) → 1
COUNTBLANK(arr)
Count of empty/null values
COUNTBLANK([1, null, "", 3]) → 2
RANK_EQ(n; arr)
Rank (descending)
RANK_EQ(4; [5, 4, 3, 2]) → 2
RANK_AVG(n; arr)
Rank with average for ties
RANK_AVG(4; [5, 4, 4, 2]) → 2.5
PERCENTILE_INC(arr; k)
Percentile (inclusive)
PERCENTILE_INC([1,2,3,4]; 0.75) → 3.25
QUARTILE_INC(arr; q)
Quartile (0--4)
QUARTILE_INC([1,2,3,4]; 1) → 1.75
CORREL(x; y)
Correlation coefficient
CORREL([1,2,3]; [2,4,6]) → 1
SLOPE(y; x)
Linear regression slope
SLOPE([2,4,6]; [1,2,3]) → 2
INTERCEPT(y; x)
Linear regression intercept
INTERCEPT([2,4,6]; [1,2,3]) → 0
FORECAST(x; y; knownX)
Linear prediction
FORECAST(4; [2,4,6]; [1,2,3]) → 8
GEOMEAN(arr)
Geometric mean
GEOMEAN([2, 8]) → 4
HARMEAN(arr)
Harmonic mean
HARMEAN([2, 8]) → 3.2
TRIMMEAN(arr; pct)
Mean excluding outliers
TRIMMEAN([1,2,3,4,100]; 0.4)
AVEDEV(arr)
Average absolute deviation
AVEDEV([2, 4, 8, 16])
DEVSQ(arr)
Sum of squared deviations
DEVSQ([2, 4, 8, 16])
SKEW(arr)
Distribution skewness
SKEW([1, 2, 3, 4, 100]) → positive
KURT(arr)
Distribution kurtosis
KURT([1, 2, 3, 4, 100]) → heavy-tailed
MAXIFS([vals; range; crit])
Conditional max
MAXIFS([[5,3,8]; [1,2,1]; 1]) → 8
MINIFS([vals; range; crit])
Conditional min
MINIFS([[5,3,8]; [1,2,1]; 1]) → 5
PERCENTILE_EXC(arr; k)
Percentile (exclusive)
PERCENTILE_EXC([1,2,3,4,5]; 0.4)
QUARTILE_EXC(arr; q)
Quartile exclusive (1--3)
QUARTILE_EXC([1,2,3,4,5]; 1)
PERCENTRANK_INC(arr; x)
Percentile rank (inclusive)
PERCENTRANK_INC([1,2,3,4]; 3) → 0.667
PERCENTRANK_EXC(arr; x)
Percentile rank (exclusive)
PERCENTRANK_EXC([1,2,3,4]; 3) → 0.6
PEARSON(x; y)
Pearson correlation (alias for CORREL)
PEARSON([1,2,3]; [2,4,6]) → 1
SUM and AVERAGE automatically skip nulls and non-numeric values, just like their spreadsheet counterparts.
Formula Conditional Aggregation
Two flavors: range-based (classic Excel) and _BY variants for arrays of objects.
JQXL implements 230+ functions from the Excel/Google Sheets function set, plus 16 JQXL-only extensions (the _BY row-object variants). This section maps coverage against the formulajs library.
Available via jq (use lowercase)
These Excel functions are not implemented as uppercase helpers because jq already provides them natively. Use the lowercase jq version.
Excel
jq equivalent
Category
SINCOSTAN
sincostan
Trig
ASINACOSATANATAN2
asinacosatanatan2
Trig
SINHCOSHTANH
sinhcoshtanh
Hyperbolic
ASINHACOSHATANH
asinhacoshatanh
Hyperbolic
EXPLOGLOG10
exploglog10
Exp/Log
LN
log (jq's log is natural log)
Exp/Log
TRUNC
trunc
Rounding
SORT
sort / sort_by(f)
Array
UNIQUE
unique / unique_by(f)
Array
TRANSPOSE
transpose
Array
NOW
now (Unix timestamp)
Date
Range-based multi-criteria functions (SUMIFS, COUNTIFS, AVERAGEIFS) are not implemented as uppercase helpers because JQXL's _BY variants (SUMIFS_BY, COUNTIFS_BY, AVERAGEIFS_BY) are more natural for JSON data. Use those instead.
Won't Add
Functions that don't apply to JQXL's JSON context, require a spreadsheet grid model, or are too niche for document formulas.