Skip to content

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 and conditions

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.