Skip to content

Join Filter Pattern

When joining two object types — for example, FamilyInstances to their FamilySymbol — some instances may not have a matching symbol in the filtered set. The join filter pattern uses a ternary with () to silently drop non-matching elements from the output.


The problem

A lookup returns undefined when no match is found. If you include that in the output, you get null fields or broken objects. What you actually want is for the element to disappear entirely from the results.


The pattern

After looking up the related object, return a structured result if found — or () if not:

(
  $symbols := $[type = "FamilySymbol" and values.category.type = "Model"];
  $symIndex := $merge($symbols.{ $string(id): $ });

  $[type = "FamilyInstance" and $exists(parent)].
  (
    $sym := $lookup($symIndex, $string(parent.id));
    $sym ? {
      "id": id,
      "name": name,
      "symbolName": $sym.name,
      "assemblyCode": $sym.values.assemblyCode
    } : ()
  )
)

() is an empty expression — it produces no output. Elements where $sym is undefined are excluded from the result array entirely.


Why () and not null

Returning null would include the element with a null value, which could cause false positives in the validator. Returning () makes the element disappear, as if it was never in the dataset.


When to use this pattern

Use this when: - You join FamilyInstances to a filtered subset of FamilySymbols - Not all instances will have a matching symbol in the filtered set - You want those unmatched instances silently excluded

Do not use this when: - The absence of a match is itself a validation finding — in that case, include the element with a computed field that the validator checks


Relation to the applicability gate

The join filter pattern and the applicability gate both remove elements from the output. The difference:

Join filter ($sym ? {...} : ()) Applicability gate ([field = true])
Trigger Lookup returned nothing Computed field is false
Position Inside .() expression After the projection
Typical use Cross-type join Conditional rule scope

Common mistakes

  • Using $sym != null ? {...} : null — returning null keeps the element in the array with a null value
  • Forgetting $exists(parent) before the lookup — instances without a parent will throw an error on $string(parent.id)