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 value900is 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→ objectlevelId→ 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.
. — navigate into a property
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: