Skip to content

Two-Step Filtering

Many DAQS rules filter in two steps — first FamilySymbols, then FamilyInstances.

This is not a workaround. It is a direct result of how Revit stores data.


Why it exists

In Revit, some data lives on the Type (FamilySymbol) and other data lives on the Instance (FamilyInstance).

  • Category → on the FamilySymbol
  • Assembly Code → on the FamilySymbol
  • Mark → on the FamilyInstance
  • Level → on the FamilyInstance

When you want to validate an instance based on its type's data, you need both objects.

For example:

All FamilyInstances in category Doors must have a Mark.

To write this rule, you need: - Category → comes from FamilySymbol.values.category - Mark → comes from FamilyInstance.values.mark

You cannot get both from a single object. The instance does not carry category. The symbol does not carry mark.


The pattern

Step 1 — find the relevant symbol IDs:

$[type = "FamilySymbol" and values.category.name = "Doors"].id

This returns a list of IDs of all door type symbols.

Step 2 — find instances whose parent is one of those symbols:

$[type = "FamilyInstance" and parent.id in $doorSymbolIds]

Combined into a single filter:

(
  $doorSymbolIds := $[type = "FamilySymbol" and values.category.name = "Doors"].id;

  $[type = "FamilyInstance" and parent.id in $doorSymbolIds].{
    "id": id,
    "type": type,
    "name": name,
    "mark": values.mark
  }
)

The ; separates the variable binding from the main query. The last expression is what the filter returns.


When to use two-step filtering

Use two steps when your scope condition involves type-level data but you are validating instance-level data — or vice versa.

Common cases:

Scope condition Validated value Steps needed
Category = Doors Instance Mark Two — category on symbol, mark on instance
Assembly Code starts with 32. Instance Mark Two — assembly code on symbol, mark on instance
isEditable = true Type Mark Two — isEditable on family, type mark on symbol
Instance on Level X Instance parameter One — everything on instance

What the ; separator does

Inside a ( ) block, ; separates statements. Variables assigned with := are available to all following statements.

(
  $symbols := $[type = "FamilySymbol" and values.category.name = "Doors"];
  $ids     := $symbols.id;

  $[type = "FamilyInstance" and parent.id in $ids].{
    "id": id,
    "name": name,
    "mark": values.mark
  }
)

The last expression is always the return value of the block.


Summary

Two-step filtering is necessary because:

  • Type data lives on FamilySymbol
  • Instance data lives on FamilyInstance
  • These are separate objects in the flat JSON array

When your rule's scope condition and its validated value are on different object types, you need two steps.