Skip to content

JSONata Syntax at a Glance

Reading JSONata — Syntax at a Glance

JSONata filters can look unfamiliar at first. This page explains every symbol you will encounter in DAQS rules — one at a time, with examples from real data.

You do not need to memorise this. Use it as a reference when a symbol in a rule is unclear.


Data Concepts: Understanding JSON Structures

Before writing queries or validations in DAQS, you need a solid understanding of how data is structured. DAQS works with JSON data, and everything you do—filters, mappings, validations—depends on how well you understand these core concepts.


1. Object

An object is the fundamental building block in JSON. It represents a single entity and contains a collection of properties.

Think of it as a "thing" with attributes.

Example

{
  "id": 123,
  "name": "Door A",
  "type": "FamilyInstance"
}

This entire structure is one object.

Key points 1

  • Objects are wrapped in { }
  • They contain key–value pairs
  • In DAQS, most elements (FamilyInstance, FamilySymbol, Level, etc.) are objects

2. Array

An array is a list of items.

These items are usually objects, but they can also be values (strings, numbers, etc.).

Example 1

[
  { "id": 1, "name": "Door A" },
  { "id": 2, "name": "Door B" }
]

This is an array of objects.

Key points 2

  • Arrays are wrapped in [ ]
  • They represent collections (e.g., all elements in a model)
  • In DAQS, your root $ is almost always an array

3. Key

A key is the name used to identify a value inside an object.

Example 2

{
  "name": "Door A"
}

Here, "name" is the key.

Key points 3

  • Keys are always strings
  • They define what the data represents
  • In DAQS, keys often map to parameter names or system fields

4. Value

A value is the data assigned to a key.

Example 3

{
  "name": "Door A",
  "width": 900
}
  • "Door A" is a string value
  • 900 is a numeric value

Value types

  • String → "Door A"
  • Number → 900
  • Boolean → true / false
  • Null → null
  • Object → { ... }
  • Array → [ ... ]

Key point 4

Everything in JSON is ultimately a value.


5. Property

A property is a combination of a key and a value.

Example 4

{
  "name": "Door A"
}
  • "name" → key
  • "Door A" → value
  • Together → property

Why this matters in DAQS

When you write queries like:

values.levelId

You are navigating through properties:

  • values → object
  • levelId → property inside that object

How These Concepts Work Together

Let’s combine everything:

[
  {
    "id": 1,
    "name": "Door A",
    "values": {
      "levelId": 1001
    }
  }
]
  • The root is an array
  • Each item is an object
  • Each object contains properties
  • Each property has a key and a value
  • Some values are nested objects

This nested structure is what you query in DAQS.


Why This Matters for DAQS

If you misunderstand this structure, your rules will fail.

Typical mistakes:

  • Treating an array like an object
  • Forgetting that a value can be null
  • Not including required properties in your filter output
  • Assuming a property always exists

In DAQS:

Your validation can only use what your filter outputs.

So if you don’t extract the right properties, your validation cannot work—no matter how correct the logic is.


Essential additions

6. Path / Accessor

How you navigate data:

values.levelId

7. Root ($)

The starting point of every query.

$

In DAQS, this is usually the full model (array of elements).


8. Filter

Selecting a subset of data:

$[type = "FamilyInstance"]

Core concept for every DAQS rule.


9. Mapping

Transforming data into a new structure:

$[type="FamilyInstance"].{
  "id": id,
  "name": name
}

Critical for shaping output for validation.


10. Null vs Missing

This one is constantly misunderstood.

  • null → exists but empty
  • missing → does not exist at all

This directly impacts validators like:

  • Should exist
  • Should be null

11. Index / Lookup (Performance concept)

For more advanced users:

$lookup($index, $string(id))

This is the difference between:

  • beginner scripts (slow)
  • production-ready DAQS rules

The data we use in examples

All examples on this page use this small JSON snippet:

[
  { "id": 617348, "type": "Family",        "name": "Door wooden",  "parent": null,                           "values": { "isEditable": true } },
  { "id": 617464, "type": "FamilySymbol",  "name": "1018x2387",    "parent": { "id": 617348, "type": "Family" }, "values": { "assemblyCode": "32.31", "fireRating": null } },
  { "id": 616521, "type": "FamilyInstance","name": "Door 1018x2387","parent": { "id": 617464, "type": "FamilySymbol" }, "values": { "mark": "D-01", "levelId": 311 } },
  { "id": 616522, "type": "FamilyInstance","name": "Door 1018x2387","parent": { "id": 617464, "type": "FamilySymbol" }, "values": { "mark": null,   "levelId": 311 } }
]

Paste this into try.jsonata.org and follow along.


$ — the input

$ refers to the entire input — the full JSON array.

$

Returns the entire array as-is.

In DAQS filters, $ is almost always the starting point.


The dot navigates into an object's property.

$.type

Returns all type values from every object in the array:

["Family", "FamilySymbol", "FamilyInstance", "FamilyInstance"]

Chain dots to go deeper:

$.parent.id

Returns the id of each object's parent (where it exists).


[ ] — filter: select where a condition is true

Square brackets after $ act as a filter predicate. Only objects where the condition is true are kept.

$[type = "FamilyInstance"]

Returns only the two FamilyInstance objects.

$[type = "FamilyInstance" and values.mark != null]

Returns only the FamilyInstance where mark is filled in.

You can also use square brackets to access an index:

$[0]

Returns the first object in the array.


{ } — object constructor: shape the output

Curly braces create a new object with only the fields you specify.

$[type = "FamilyInstance"].{
  "id": id,
  "name": name,
  "mark": values.mark
}

Returns:

[
  { "id": 616521, "name": "Door 1018x2387", "mark": "D-01" },
  { "id": 616522, "name": "Door 1018x2387", "mark": null }
]

This is how DAQS filters shape their output for the validator. The left side is the output field name (a string you choose). The right side is the JSONata expression that produces the value.


( ) — expression block: group statements

Parentheses wrap a block of expressions. In DAQS filters, the entire query is almost always wrapped in ( ).

(
  $[type = "FamilyInstance"].{
    "id": id,
    "name": name,
    "mark": values.mark
  }
)

This is the standard form for all DAQS filter queries. The outer parentheses have no effect on the result — they are a convention for readability.


= and != — equality comparison

Used inside filter predicates [ ].

$[type = "FamilyInstance"]       /* equal */
$[type != "Family"]              /* not equal */

and / or — combine conditions

$[type = "FamilyInstance" and values.mark = null]
$[type = "Family" or type = "FamilySymbol"]

! — not / negation (rare in DAQS)

JSONata uses $not(...) for negation rather than a ! prefix.

$[type = "FamilyInstance" and $not(values.mark = "")]

You will rarely write this directly in DAQS filters.


; — separator between variable bindings (advanced)

Semicolons separate variable bindings inside an expression block. You will see this in more advanced filters:

(
  $symbols := $[type = "FamilySymbol"];
  $instances := $[type = "FamilyInstance"];
  ...
)

Each ; ends one statement and starts the next. The last expression in the block is the return value.


$$ — the root context

$$ always refers to the root input — the full dataset — regardless of where in the expression you are.

Inside a nested expression or function, $ refers to the current item being processed. $$ lets you reach back to the full array.

(
  $paramMeta := $merge(
    $$[type = "Parameter"].{ $string(values.guid): values.name }
  );

  $[type = "FamilyInstance"].{
    "id": id,
    "name": name
  }
)

Here $$[type = "Parameter"] queries the full dataset even though the outer expression is already inside a block. Without $$, $ inside the helper expression would refer only to the current context, not the full array.

You will see $$ most often when building parameter metadata lookup tables inside a function scope.


* — wildcard property access

The asterisk selects all properties of an object.

$.values.*

Used in advanced patterns to access all values without knowing their names in advance. Relevant when working with shared parameters that have p_<guid> keys.


" " — string literal

Double quotes define a literal string value.

$[type = "FamilyInstance"]

"FamilyInstance" is the string to match against. Always use double quotes — single quotes are not valid in JSONata.


Quick reference table

Symbol Meaning Example
$ Current context / root $
$$ Root context (from nested scope) $$[type = "Parameter"]
. Navigate into property $.type or values.mark
[ ] Filter predicate $[type = "FamilyInstance"]
{ } Object constructor { "id": id, "name": name }
( ) Expression block ( $[...].{ ... } )
= Equal type = "Family"
!= Not equal values.mark != null
and Logical AND type = "X" and id = 1
or Logical OR type = "X" or type = "Y"
; Statement separator $a := ...; $b := ...
* Wildcard values.*
" " String literal "FamilyInstance"

Next

Now that the symbols make sense, walk through a complete rule:

👉 First Rule Explained