Skip to content

The DAQS Data Model

DAQS rules do not query Revit directly. They query the JSON file that DAQS Assist exports from the model.

Understanding how that JSON is organised prevents an entire category of mistakes.


Revit is hierarchical — DAQS is not

In Revit, data is nested. A Family contains Types, a Type contains Instances, an Instance belongs to a Level. You navigate this hierarchy in the UI by opening panels, clicking Edit Type, expanding trees.

DAQS exports this differently.

The DAQS JSON is a flat array. Every object — Family, Type, Instance, Level, Parameter — sits side by side in the same list.

[
  { "id": 617348, "type": "Family",        "name": "Door wooden", ... },
  { "id": 617464, "type": "FamilySymbol",  "name": "1018x2387",  ... },
  { "id": 616521, "type": "FamilyInstance","name": "1018x2387",  ... },
  { "id": 311,    "type": "Level",         "name": "00 begane grond", ... }
]

There is no nesting. A FamilyInstance does not contain its type's data. A FamilySymbol does not contain a list of its instances.


Relationships are expressed by parent.id

Instead of nesting, DAQS uses references.

A FamilyInstance points to its FamilySymbol via parent:

{
  "id": 616521,
  "type": "FamilyInstance",
  "parent": {
    "id": 617464,
    "type": "FamilySymbol"
  }
}

A FamilySymbol points to its Family the same way:

{
  "id": 617464,
  "type": "FamilySymbol",
  "parent": {
    "id": 617348,
    "type": "Family"
  }
}

This is why DAQS is called relational — objects relate to each other through IDs, not through nesting.


What this means for rule writing

Data does not cascade down automatically

In Revit, when you select an instance, you can immediately open Type Properties and see the Assembly Code. The UI does this lookup for you.

In DAQS, you must do it yourself.

If you want to read assemblyCode while validating a FamilyInstance, you must:

  1. Find the FamilyInstance
  2. Read its parent.id to get the FamilySymbol ID
  3. Look up the FamilySymbol by that ID
  4. Read assemblyCode from the symbol's values

This is what two-step filtering is about.

Every rule starts with a type filter

Because everything is in one flat array, the first thing every rule does is narrow down to the relevant object type:

$[type = "FamilyInstance"]
$[type = "FamilySymbol"]
$[type = "Room"]

Without this, your query operates on the entire dataset.

The same structure, every time

Every object — regardless of type — follows the same shape:

{
  "id":     ...,
  "type":   "...",
  "name":   "...",
  "parent": { "id": ..., "type": "..." } or null,
  "values": { ... }
}

Once you know this shape, you can navigate any object in the dataset.


Why flat instead of nested?

A nested structure would mirror the Revit UI more closely, but it creates problems:

  • An instance would need to embed its full type data — duplicated for every instance of that type
  • Adding a new object type (like a MechanicalSystem) would require a new nesting level
  • JSONata queries on deeply nested structures become complex and fragile

A flat, relational structure keeps every object independent and consistent. Rules stay predictable regardless of how complex the model is.


Next

For the detailed field-by-field reference of the JSON structure, see:

👉 Data Structure Reference

For how to navigate relationships between objects in filter expressions, see:

👉 Two-Step Filtering