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.