Skip to content

Filtering FamilyInstance objects by category via their FamilySymbol

When filtering placed elements (FamilyInstance) by category, you must remember one thing:

The category lives on the FamilySymbol, not on the FamilyInstance.

This filter shows the correct and explicit way to select only door instances.

(
  /* Filter FamilySymbols by category */
  $familySymbols := $[
    type = "FamilySymbol"
    and values.category.label = "OST_Doors"
  ].id;

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

What this filter does (plain language)

“Select all placed door elements by first selecting door types, then finding all instances that use those types.”

This is a two-step process by design.


Step 1 — select the relevant FamilySymbols (types)

$familySymbols := $[
  type = "FamilySymbol"
  and values.category.label = "OST_Doors"
].id;

This step:

  • Selects FamilySymbols only
  • Limits them to the Doors category
  • Extracts their id
  • Stores those IDs in $familySymbols

Result (conceptually):

[617464, 617670, 617812, ...]

Think of this as:

“These are all the door types in the model.”


Why category filtering happens here

Category information:

values.category.label
  • Exists reliably on FamilySymbol
  • Is stable and API-based (OST_*)
  • Represents the category of the type

While instances belong to a category in Revit, in DAQS rules you should always anchor category logic at the type level.

This avoids:

  • Ambiguity
  • Inconsistent results
  • Duplicate or misleading filters

Step 2 — select FamilyInstances that reference those symbols

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

This step:

  • Selects all placed elements
  • Keeps only those whose parent.id
  • Matches one of the previously selected FamilySymbols

In other words:

“Give me all instances of door types.”


Why parent.id is essential

A FamilyInstance contains this reference:

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

This is the only reliable link between:

  • A placed element
  • Its family type
  • Its category and type-level data

Never infer category or type context directly from the instance.


What the filter output represents

Each result represents:

One placed door in the model, with a reference to its type.

Example output:

{
  "id": 616521,
  "type": "FamilyInstance",
  "name": "1018x2387 – kader 40mm HPL",
  "parent": 617464
}

This output is now suitable for:

  • Instance-level validation
  • Placement checks
  • Level or host validation
  • Reporting issues per placed element

Common mistakes this pattern avoids

Filtering instances directly by category

values.category.label = "OST_Doors"

❌ Fragile and inconsistent on instances.


Mixing type and instance logic

$[type = "FamilyInstance" and values.category.label = "OST_Doors"]

❌ Category logic belongs on the type.


Skipping the two-step approach

$[type = "FamilyInstance"]

⚠️ Too broad — loses intent and precision.


Correct mental model

Categories define types. Instances reference types. So category-based instance filtering always goes via the type.

Once users understand this, a large class of incorrect rules disappears.