Filtering with exclusion lists — excluding categories safely
Note
This example introduces exclusion-based filtering. Use this pattern only when the rule scope is intentionally broad.
Sometimes a rule should apply to almost everything, except a few specific categories.
In those cases, using an exclusion list is clearer and safer than trying to list everything you do want.
(
/* Category Exclusion */
$CategoryExclusion := ["OST_Doors", "OST_Windows"];
$[
type = "FamilySymbol"
and $not(values.category.label in $CategoryExclusion)
].{
"id": id,
"type": type,
"name": name,
"assemblyCode": values.assemblyCode
}
)
What this filter does (plain language)
“Select all FamilySymbols except those that belong to the Doors or Windows categories.”
Everything else is included.
Breaking down the new parts
1. Exclusion list
$CategoryExclusion := ["OST_Doors", "OST_Windows"];
This list defines:
“These categories must be ignored by this rule.”
Use exclusion lists when:
- The number of excluded categories is small
- The allowed scope is broad or evolving
2. Negation using $not(...)
$not(values.category.label in $CategoryExclusion)
This means:
- First check whether the category is in the exclusion list
- Then invert the result
So:
- If the category is in the list → excluded
- If the category is not in the list → included
Why $not() is used instead of !=
You might be tempted to write:
values.category.label != "OST_Doors"
This is wrong when:
- You need to exclude multiple categories
- More categories may be added later
$not(... in ...):
- Scales cleanly
- Is explicit
- Avoids chained
andconditions
Inclusion vs exclusion — when to use which
| Situation | Use |
|---|---|
| Small, fixed set of allowed categories | Inclusion list |
| Broad scope, few categories to ignore | Exclusion list |
| Rule tied to a specific discipline | Inclusion |
| Generic or cross-discipline rule | Exclusion |
Common mistakes to avoid
Forgetting $not()
values.category.label in $CategoryExclusion
❌ This does the opposite of what you want.
Negating the wrong part
$not(values.category.label) in $CategoryExclusion
❌ Syntax error and incorrect logic.
Mixing inclusion and exclusion in one filter
values.category.label in $Include and $not(values.category.label in $Exclude)
⚠️ Possible, but error-prone. Avoid unless necessary and well-documented.
Important caution
Exclusion filters are powerful and dangerous.
If a new category is introduced in the model:
- It will automatically be included
- Possibly without you realising
Use exclusion lists only when this behaviour is intentional.
Rule of thumb
Inclusion defines intent. Exclusion defines exceptions.
Choose based on which is clearer for the rule’s purpose.
Common exclusion: Detail Items
One category that is frequently excluded by default is OST_DetailComponents (Detail Items in the Revit UI).
Despite having category.type = “Model”, Detail Items carry no model parameters and always fail generic parameter checks — causing false positives.
For the full explanation, see Detail Items and False Positives.