Skip to content

d2path examples

A validated gallery of d2path expressions grouped by category. Every expression, its input, and its result are checked by the test suite (packages/dhis2w-ql/tests/test_doc_examples.py) and rendered from dhis2w_ql.doc_examples.DOC_EXAMPLES — do not edit by hand. Rebuild via make docs-d2path (chained into make docs-build).

Total examples: 140.

Filtering & projection

where()

Keep the matching sub-object, then navigate into it.

name.where(use = "official").family

Input:

{
  "name": [
    {
      "use": "official",
      "given": [
        "Ada",
        "Lovelace"
      ],
      "family": "King"
    },
    {
      "use": "nick",
      "given": [
        "Countess"
      ]
    }
  ]
}

Result:

[
  "King"
]

Filter a collection of objects by a numeric predicate on $this.

items.where(qty > 2)

Input:

{
  "items": [
    {
      "qty": 1
    },
    {
      "qty": 5
    },
    {
      "qty": 3
    }
  ]
}

Result:

[
  {
    "qty": 5
  },
  {
    "qty": 3
  }
]

Select one telecom channel by its system, then read its value.

telecom.where(system = "phone").value

Input:

{
  "telecom": [
    {
      "system": "phone",
      "value": "555-1"
    },
    {
      "system": "email",
      "value": "a@b.c"
    }
  ]
}

Result:

[
  "555-1"
]

Filter data elements by valueType, then read the surviving names.

elements.where(valueType = "NUMBER").name

Input:

{
  "elements": [
    {
      "name": "Malaria cases",
      "valueType": "NUMBER"
    },
    {
      "name": "Clinical notes",
      "valueType": "TEXT"
    }
  ]
}

Result:

[
  "Malaria cases"
]

select()

Reshape each item into a new object with an object constructor.

options.select({ code: code, display: name })

Input:

{
  "options": [
    {
      "code": "M",
      "name": "Male"
    },
    {
      "code": "F",
      "name": "Female"
    }
  ]
}

Result:

[
  {
    "code": "M",
    "display": "Male"
  },
  {
    "code": "F",
    "display": "Female"
  }
]

Map every item through an arithmetic expression on $this.

scores.select($this * 2)

Input:

{
  "scores": [
    1,
    2,
    3
  ]
}

Result:

[
  2.0,
  4.0,
  6.0
]

Project and transform a field from each item.

people.select(name.upper())

Input:

{
  "people": [
    {
      "name": "ada"
    },
    {
      "name": "bob"
    }
  ]
}

Result:

[
  "ADA",
  "BOB"
]

Rename organisation-unit fields into a compact projection.

orgUnits.select({ id: id, depth: level })

Input:

{
  "orgUnits": [
    {
      "id": "SL",
      "level": 1
    },
    {
      "id": "Bo",
      "level": 2
    }
  ]
}

Result:

[
  {
    "id": "SL",
    "depth": 1
  },
  {
    "id": "Bo",
    "depth": 2
  }
]

iif()

Return one of two values based on a predicate.

iif(gender = "male", "M", "F")

Input:

{
  "gender": "male"
}

Result:

[
  "M"
]

Branch on a boolean field.

iif(active, "on", "off")

Input:

{
  "active": false
}

Result:

[
  "off"
]

Threshold a numeric field into a label.

iif(qty > 10, "high", "low")

Input:

{
  "qty": 5
}

Result:

[
  "low"
]

Label a coverage value that clears a target.

iif(value > 50, "high", "low")

Input:

{
  "value": 87
}

Result:

[
  "high"
]

Existence & logic

exists()

With no argument, report whether the collection is non-empty.

codes.exists()

Input:

{
  "codes": [
    "ANC1"
  ]
}

Result:

[
  true
]

An empty (or missing) collection does not exist.

orgUnits.exists()

Input:

{
  "orgUnits": []
}

Result:

[
  false
]

With a predicate, report whether any item satisfies it.

rows.exists(value > 20)

Input:

{
  "rows": [
    {
      "value": 12
    },
    {
      "value": 30
    }
  ]
}

Result:

[
  true
]

all()

True when every item satisfies the predicate.

rows.all(active)

Input:

{
  "rows": [
    {
      "active": true
    },
    {
      "active": true
    }
  ]
}

Result:

[
  true
]

A single failing item makes all false.

stages.all(completed)

Input:

{
  "stages": [
    {
      "completed": true
    },
    {
      "completed": false
    }
  ]
}

Result:

[
  false
]

empty()

An empty collection is empty.

tags.empty()

Input:

{
  "tags": []
}

Result:

[
  true
]

A non-empty collection is not empty.

roles.empty()

Input:

{
  "roles": [
    "ADMIN"
  ]
}

Result:

[
  false
]

A missing field navigates to the empty collection, which is empty.

closedDate.empty()

Input:

{
  "openingDate": "2020-01-01"
}

Result:

[
  true
]

not()

Negate a boolean field.

verified.not()

Input:

{
  "verified": false
}

Result:

[
  true
]

Negate a true flag.

flag.not()

Input:

{
  "flag": true
}

Result:

[
  false
]

An empty focus is falsy, so not() returns true.

middleName.not()

Input:

{
  "firstName": "Ada"
}

Result:

[
  true
]

Subsetting & set operations

first()

Keep the first item of a collection.

first()

Input:

[
  10,
  20,
  30
]

Result:

[
  10
]

Take the first name after navigating a repeated field.

names.first()

Input:

{
  "names": [
    "ANC 1st visit",
    "BCG doses"
  ]
}

Result:

[
  "ANC 1st visit"
]

last()

Keep the last item of a collection.

last()

Input:

[
  10,
  20,
  30
]

Result:

[
  30
]

Read the most recent period from an ordered list.

periods.last()

Input:

{
  "periods": [
    "202601",
    "202602",
    "202603"
  ]
}

Result:

[
  "202603"
]

tail()

Drop the first item, keeping the rest.

tail()

Input:

[
  10,
  20,
  30
]

Result:

[
  20,
  30
]

The tail of a single-element collection is empty.

names.tail()

Input:

{
  "names": [
    "ANC 1st visit"
  ]
}

Result:

[]

skip()

Drop the first N items.

skip(2)

Input:

[
  10,
  20,
  30,
  40
]

Result:

[
  30,
  40
]

Skipping past the end yields the empty collection.

skip(9)

Input:

[
  10,
  20
]

Result:

[]

take()

Keep the first N items.

take(2)

Input:

[
  10,
  20,
  30,
  40
]

Result:

[
  10,
  20
]

Taking zero items yields the empty collection.

take(0)

Input:

[
  10,
  20
]

Result:

[]

count()

Count the items in a collection.

count()

Input:

[
  1,
  2,
  3,
  4
]

Result:

[
  4
]

Count a repeated field after navigation.

tags.count()

Input:

{
  "tags": [
    "malaria",
    "epi",
    "anc"
  ]
}

Result:

[
  3
]

distinct()

Drop duplicate strings, preserving first-seen order.

tags.distinct()

Input:

{
  "tags": [
    "a",
    "b",
    "a",
    "c",
    "b"
  ]
}

Result:

[
  "a",
  "b",
  "c"
]

De-duplicate a numeric collection.

values.distinct()

Input:

{
  "values": [
    1,
    1,
    2,
    3,
    3,
    3
  ]
}

Result:

[
  1,
  2,
  3
]

Chain into count() to count the unique values.

codes.distinct().count()

Input:

{
  "codes": [
    "A",
    "B",
    "A"
  ]
}

Result:

[
  2
]

isDistinct()

True when a collection has no duplicates.

codes.isDistinct()

Input:

{
  "codes": [
    "A",
    "B",
    "C"
  ]
}

Result:

[
  true
]

Repeated organisation-unit levels are not distinct.

orgUnits.level.isDistinct()

Input:

{
  "orgUnits": [
    {
      "level": 2
    },
    {
      "level": 3
    },
    {
      "level": 2
    }
  ]
}

Result:

[
  false
]

union()

Union with itself collapses to the distinct set.

codes.union(codes)

Input:

{
  "codes": [
    "ANC",
    "BCG",
    "ANC"
  ]
}

Result:

[
  "ANC",
  "BCG"
]

Merge in a projected collection, de-duplicating the result.

union(select($this + 100))

Input:

[
  1,
  2,
  3
]

Result:

[
  1,
  2,
  3,
  101.0,
  102.0,
  103.0
]

combine()

Append another collection, keeping duplicates (unlike union).

combine(tail())

Input:

[
  10,
  20,
  30
]

Result:

[
  10,
  20,
  30,
  20,
  30
]

Concatenating a collection with a copy of itself doubles it.

combine(take(2))

Input:

[
  1,
  2
]

Result:

[
  1,
  2,
  1,
  2
]

Strings

substring()

Take a fixed-length slice from a start offset.

name.substring(0, 3)

Input:

{
  "name": "Albendazole"
}

Result:

[
  "Alb"
]

Omit the length to slice to the end of the string.

code.substring(2)

Input:

{
  "code": "DE1234"
}

Result:

[
  "1234"
]

Slice a prefix for grouping or matching.

name.substring(0, 4)

Input:

{
  "name": "Pentavalent"
}

Result:

[
  "Pent"
]

A length past the end of the string clips to what remains.

code.substring(3, 10)

Input:

{
  "code": "DE01"
}

Result:

[
  "1"
]

upper()

Upper-case a string.

name.upper()

Input:

{
  "name": "malaria"
}

Result:

[
  "MALARIA"
]

A non-string (or missing) focus yields the empty collection.

label.upper()

Input:

{
  "label": null
}

Result:

[]

lower()

Lower-case a string.

name.lower()

Input:

{
  "name": "BCG"
}

Result:

[
  "bcg"
]

Normalise a code to lower case.

code.lower()

Input:

{
  "code": "DE_ANC"
}

Result:

[
  "de_anc"
]

length()

Report a string's character count.

name.length()

Input:

{
  "name": "Pentavalent"
}

Result:

[
  11
]

A missing field yields the empty collection, not zero.

nickname.length()

Input:

{
  "name": "Ada"
}

Result:

[]

trim()

Strip leading and trailing whitespace.

label.trim()

Input:

{
  "label": "  ANC 1st visit  "
}

Result:

[
  "ANC 1st visit"
]

Trim removes tabs and newlines too.

code.trim()

Input:

{
  "code": "\tDE01\n"
}

Result:

[
  "DE01"
]

toChars()

Explode a string into its characters.

code.toChars()

Input:

{
  "code": "DE01"
}

Result:

[
  [
    "D",
    "E",
    "0",
    "1"
  ]
]

A single-character string becomes a one-element list.

flag.toChars()

Input:

{
  "flag": "Y"
}

Result:

[
  [
    "Y"
  ]
]

startsWith()

Test a string prefix.

name.startsWith("ANC")

Input:

{
  "name": "ANC 1st visit"
}

Result:

[
  true
]

A non-matching prefix is false.

name.startsWith("BCG")

Input:

{
  "name": "ANC 1st visit"
}

Result:

[
  false
]

endsWith()

Test a string suffix.

name.endsWith("visit")

Input:

{
  "name": "ANC 1st visit"
}

Result:

[
  true
]

A non-matching suffix is false.

filename.endsWith(".csv")

Input:

{
  "filename": "export.json"
}

Result:

[
  false
]

contains()

Test whether a string contains a substring (method form).

name.contains("1st")

Input:

{
  "name": "ANC 1st visit"
}

Result:

[
  true
]

A missing substring is not contained.

name.contains("xyz")

Input:

{
  "name": "ANC 1st visit"
}

Result:

[
  false
]

indexOf()

Find the zero-based offset of a substring.

name.indexOf("visit")

Input:

{
  "name": "ANC 1st visit"
}

Result:

[
  8
]

A substring that is absent returns -1.

name.indexOf("xyz")

Input:

{
  "name": "ANC 1st visit"
}

Result:

[
  -1
]

replace()

Replace every occurrence of a literal substring.

path.replace("/", " > ")

Input:

{
  "path": "Sierra Leone/Bo/Ngelehun"
}

Result:

[
  "Sierra Leone > Bo > Ngelehun"
]

Swap a separator character in a code.

code.replace("_", "-")

Input:

{
  "code": "DE_01"
}

Result:

[
  "DE-01"
]

matches()

Test a string against a regular expression.

code.matches("^[A-Z]{2}[0-9]+$")

Input:

{
  "code": "DE01"
}

Result:

[
  true
]

A pattern that does not match returns false.

code.matches("^[0-9]+$")

Input:

{
  "code": "DE01"
}

Result:

[
  false
]

split()

Split a string on a separator into a collection.

period.split("-")

Input:

{
  "period": "2026-Q1-BCG"
}

Result:

[
  "2026",
  "Q1",
  "BCG"
]

A separator that is absent yields the whole string as one element.

code.split("/")

Input:

{
  "code": "ABC"
}

Result:

[
  "ABC"
]

join()

Join a collection with a separator.

parts.join("-")

Input:

{
  "parts": [
    "2026",
    "Q1",
    "BCG"
  ]
}

Result:

[
  "2026-Q1-BCG"
]

Build a comma-separated label from tags.

tags.join(", ")

Input:

{
  "tags": [
    "malaria",
    "epi"
  ]
}

Result:

[
  "malaria, epi"
]

Math & aggregates

sum()

Sum a numeric collection (aggregates return decimals).

values.sum()

Input:

{
  "values": [
    1,
    2,
    3
  ]
}

Result:

[
  6.0
]

Analytics values arrive as strings; sum coerces them to numbers.

rows.value.sum()

Input:

{
  "rows": [
    {
      "value": "12"
    },
    {
      "value": "7"
    },
    {
      "value": "30"
    }
  ]
}

Result:

[
  49.0
]

min()

Smallest value in a numeric collection.

deltas.min()

Input:

{
  "deltas": [
    -3,
    5,
    -1
  ]
}

Result:

[
  -3.0
]

Minimum over string-typed analytics values.

rows.value.min()

Input:

{
  "rows": [
    {
      "value": "12"
    },
    {
      "value": "7"
    }
  ]
}

Result:

[
  7.0
]

max()

Largest value in a numeric collection.

deltas.max()

Input:

{
  "deltas": [
    -3,
    5,
    -1
  ]
}

Result:

[
  5.0
]

Maximum over string-typed analytics values.

rows.value.max()

Input:

{
  "rows": [
    {
      "value": "12"
    },
    {
      "value": "7"
    }
  ]
}

Result:

[
  12.0
]

avg()

Arithmetic mean of a numeric collection.

scores.avg()

Input:

{
  "scores": [
    10,
    20,
    30
  ]
}

Result:

[
  20.0
]

Average of string-typed analytics values.

rows.value.avg()

Input:

{
  "rows": [
    {
      "value": "12"
    },
    {
      "value": "8"
    }
  ]
}

Result:

[
  10.0
]

abs()

Absolute value of a number.

balance.abs()

Input:

{
  "balance": -12.5
}

Result:

[
  12.5
]

Absolute value of a scalar focus.

abs()

Input:

-3

Result:

[
  3.0
]

round()

Round to a given number of decimal places.

value.round(2)

Input:

{
  "value": 3.14159
}

Result:

[
  3.14
]

Round a coverage figure to one decimal place.

coverage.round(1)

Input:

{
  "coverage": 87.456
}

Result:

[
  87.5
]

Omitting the precision rounds to the nearest whole number.

rate.round()

Input:

{
  "rate": 3.6
}

Result:

[
  4.0
]

Conversion & temporal

toInteger()

Parse a numeric string into an integer.

value.toInteger()

Input:

{
  "value": "42"
}

Result:

[
  42
]

A decimal is truncated toward zero.

score.toInteger()

Input:

{
  "score": 3.9
}

Result:

[
  3
]

toDecimal()

Parse a numeric string into a decimal.

value.toDecimal()

Input:

{
  "value": "3.14"
}

Result:

[
  3.14
]

Widen an integer into a decimal.

total.toDecimal()

Input:

{
  "total": 7
}

Result:

[
  7.0
]

toString()

Render a number as a string.

level.toString()

Input:

{
  "level": 3
}

Result:

[
  "3"
]

A boolean renders as the canonical true/false text.

active.toString()

Input:

{
  "active": true
}

Result:

[
  "true"
]

A null (or missing) focus yields the empty collection.

value.toString()

Input:

{
  "value": null
}

Result:

[]

today()

Current date as an ISO-8601 string; the exact value varies at runtime.

today()

Result (varies at runtime; shape shown):

[
  "2026-07-11"
]

An ISO date is always ten characters long.

today().length()

Result:

[
  10
]

Slice the year out of today's date; the value varies at runtime.

today().substring(0, 4)

Result (varies at runtime; shape shown):

[
  "2026"
]

now()

Current timestamp as an ISO-8601 string; the exact value varies at runtime.

now()

Result (varies at runtime; shape shown):

[
  "2026-07-11T09:00:00.000000"
]

Slice the date portion out of the current timestamp; the value varies at runtime.

now().substring(0, 10)

Result (varies at runtime; shape shown):

[
  "2026-07-11"
]

Operators

operator-implies

a implies b is false only when a holds but b does not.

active implies verified

Input:

{
  "active": true,
  "verified": false
}

Result:

[
  false
]

A false antecedent makes implies vacuously true.

isDraft implies reviewed

Input:

{
  "isDraft": false,
  "reviewed": false
}

Result:

[
  true
]

A true antecedent with a true consequent holds.

verified implies active

Input:

{
  "verified": true,
  "active": true
}

Result:

[
  true
]

operator-in

Test membership of a scalar in an array literal.

valueType in ["NUMBER", "INTEGER"]

Input:

{
  "valueType": "NUMBER"
}

Result:

[
  true
]

A value outside the set is not a member.

status in ["ACTIVE", "COMPLETED"]

Input:

{
  "status": "CANCELLED"
}

Result:

[
  false
]

operator-concat

+ concatenates two strings.

firstName + " " + lastName

Input:

{
  "firstName": "Ada",
  "lastName": "Lovelace"
}

Result:

[
  "Ada Lovelace"
]

Prefix a field with a string literal to build a label.

"OU-" + code

Input:

{
  "code": "SL01"
}

Result:

[
  "OU-SL01"
]

Build an analytics dimension key from fields.

dx + "." + pe

Input:

{
  "dx": "fbfJHSPpUQD",
  "pe": "202601"
}

Result:

[
  "fbfJHSPpUQD.202601"
]

operator-arithmetic

/ is true division and keeps the fraction.

7 / 2

Result:

[
  3.5
]

div is integer division, truncating toward zero.

7 div 2

Result:

[
  3.0
]

mod is the remainder.

7 mod 2

Result:

[
  1.0
]

Unary minus negates a number (arithmetic is decimal-valued).

-delta

Input:

{
  "delta": 5
}

Result:

[
  -5.0
]

operator-xor

xor is true when exactly one side holds.

smsEnabled xor emailEnabled

Input:

{
  "smsEnabled": true,
  "emailEnabled": false
}

Result:

[
  true
]

Both sides true is not exclusive, so xor is false.

draft xor published

Input:

{
  "draft": true,
  "published": true
}

Result:

[
  false
]

operator-not-match

!~ is true when the case-insensitive substring is absent.

name !~ "malaria"

Input:

{
  "name": "BCG doses"
}

Result:

[
  true
]

~ matches case-insensitively, so !~ is false when it would match.

name !~ "bcg"

Input:

{
  "name": "BCG doses"
}

Result:

[
  false
]

operator-contains

Infix contains tests membership in a collection.

orgUnitGroups contains "CHW"

Input:

{
  "orgUnitGroups": [
    "CHW",
    "PHU"
  ]
}

Result:

[
  true
]

A value not in the collection is not contained.

orgUnitGroups contains "MOH"

Input:

{
  "orgUnitGroups": [
    "CHW",
    "PHU"
  ]
}

Result:

[
  false
]

With a string on both sides, infix contains is a substring test.

name contains "ov"

Input:

{
  "name": "Lovelace"
}

Result:

[
  true
]

operator-is

is Integer tests for an integer value.

value is Integer

Input:

{
  "value": 42
}

Result:

[
  true
]

is Decimal tests for a floating-point value.

value is Decimal

Input:

{
  "value": 3.14
}

Result:

[
  true
]

is String tests for a string value.

value is String

Input:

{
  "value": "NUMBER"
}

Result:

[
  true
]

is Boolean tests for a boolean value.

value is Boolean

Input:

{
  "value": true
}

Result:

[
  true
]

is Object tests for a structured node.

value is Object

Input:

{
  "value": {
    "k": 1
  }
}

Result:

[
  true
]

A numeric string is a String, not an Integer.

code is Integer

Input:

{
  "code": "42"
}

Result:

[
  false
]

existential-comparison

> over a repeated field is true when any item exceeds the scalar.

items.qty > 2

Input:

{
  "items": [
    {
      "qty": 1
    },
    {
      "qty": 5
    }
  ]
}

Result:

[
  true
]

= holds when any value in the collection matches.

given = "Ada"

Input:

{
  "given": [
    "Ada",
    "Grace"
  ]
}

Result:

[
  true
]

!= means no pair is equal, so a present match makes it false.

given != "Ada"

Input:

{
  "given": [
    "Ada",
    "Grace"
  ]
}

Result:

[
  false
]

< holds when some value falls below the scalar.

levels < 3

Input:

{
  "levels": [
    4,
    2
  ]
}

Result:

[
  true
]

~ holds when any value matches case-insensitively.

codes ~ "anc"

Input:

{
  "codes": [
    "ANC1",
    "BCG"
  ]
}

Result:

[
  true
]

!~ means no value matches, so a present match makes it false.

codes !~ "anc"

Input:

{
  "codes": [
    "ANC1",
    "BCG"
  ]
}

Result:

[
  false
]

Literals & navigation

literal-date

A @-prefixed date literal evaluates to its ISO-8601 string.

@2026-06-23

Result:

[
  "2026-06-23"
]

Compare an event date against a date literal (ISO strings order lexically).

eventDate > @2026-01-01

Input:

{
  "eventDate": "2026-06-23"
}

Result:

[
  true
]

A date literal equals a matching ISO date string.

eventDate = @2026-06-23

Input:

{
  "eventDate": "2026-06-23"
}

Result:

[
  true
]

literal-datetime

A @-prefixed datetime literal evaluates to its ISO-8601 string.

@2026-06-23T12:00:00

Result:

[
  "2026-06-23T12:00:00"
]

Compare a timestamp field against a datetime literal.

lastUpdated >= @2026-06-23T00:00:00

Input:

{
  "lastUpdated": "2026-06-23T12:30:00"
}

Result:

[
  true
]

path-navigation

A positive integer subscript indexes a collection.

coding[0]

Input:

{
  "coding": [
    {
      "x": 1
    },
    {
      "x": 2
    }
  ]
}

Result:

[
  {
    "x": 1
  }
]

An out-of-bounds index yields the empty collection, not an error.

coding[9]

Input:

{
  "coding": [
    {
      "x": 1
    },
    {
      "x": 2
    }
  ]
}

Result:

[]

An integer-valued index may be negative, counting from the end.

coding[pos]

Input:

{
  "coding": [
    {
      "x": 1
    },
    {
      "x": 2
    },
    {
      "x": 3
    }
  ],
  "pos": -1
}

Result:

[
  {
    "x": 3
  }
]

A string subscript reaches keys that are not identifiers.

attributes["Birth date"]

Input:

{
  "attributes": {
    "Birth date": "2000-01-01"
  }
}

Result:

[
  "2000-01-01"
]

Each navigation hop flattens one level of nested collections.

orgUnits.ancestors.name

Input:

{
  "orgUnits": [
    {
      "ancestors": [
        {
          "name": "Sierra Leone"
        },
        {
          "name": "Bo"
        }
      ]
    }
  ]
}

Result:

[
  "Sierra Leone",
  "Bo"
]