Skip to content

Combining data from the symbol and the instance

⚠️ Advanced composition pattern

This chapter combines multiple advanced concepts: symbol indexing, instance enrichment, shared-parameter access, and domain-based filtering.

Use this pattern only after understanding the earlier chapters.

This filter combines the data of the symbol and the instance to one single object.

(
  /* All relevant GUIDs in one place */
  $paramGuids := {
    "NLRS_C_SfB_tabel_1_code": "7b4acbe7-dcd9-4e30-85a5-98bc8a746427"
  };

  /* Build one lookup table with metadata per GUID */
  $paramMetaByGuid := $merge(
    $$[type = "Parameter" and values.guid in $paramGuids.*].{
      $string(values.guid): {
        "paramExist": true,
        "guid": values.guid,
        "name": values.name
      }
    }
  );

  /* Shared parameter helper */
  $getSharedParam := function($object, $logicalName){
    (
      $guid := $lookup($paramGuids, $logicalName);
      $meta := $guid ? $lookup($paramMetaByGuid, $string($guid)) : undefined;
      $sp   := $guid and $exists($object.values)
        ? $lookup($object.values, "p_" & $guid)
        : undefined;

      {
        "exists":   $exists($sp),
        "value":    $exists($sp) ? $sp.value : null,
        "valueAsString": $exists($sp) ? $sp.valueAsString : null,
        "guid":     $meta ? $meta.guid : $guid,
        "name":     $meta ? $meta.name : $logicalName
      }
    )
  };

  /* AssemblyCode inclusion regex */
  $assemblyCodeIncluded := /^5/i;

  /* Category Exclusion */
  $CategoryExclusion := ["OST_DetailComponents"];

  /* Filter FamilySymbols */
  $symbols :=
    $[
      type = "FamilySymbol"
      and values.category.type = "Model"
      and $not(values.category.label in $CategoryExclusion)
      and $string(values.assemblyCode) ~> $assemblyCodeIncluded
    ];

  /* Index symbols by id */
  $symIndex := $merge($symbols.{$string(id): $});

  /* Main query over FamilyInstances */
  $[type = "FamilyInstance" and $exists(parent)].(
    $sym := $lookup($symIndex, $string(parent.id));
    $sym ?
    {
      "id": id,
      "type": type,
      "name": name,
      "Category": $sym.values.category.label,
      "assemblyCode": $sym.values.assemblyCode,
      "NLRS_C_SfB_tabel_1_code": $getSharedParam($, "NLRS_C_SfB_tabel_1_code")
    }
    : ()
  )
)

getting data from FamilySymbol into FamilyInstance

This rule is the canonical example of something users must understand:

Not all data lives on the instance.

What lives where (Revit reality)

Object Typical data
Family Editable, name, category
FamilySymbol (Type) Assembly Code, Category, Type parameters
FamilyInstance Location, Level, Instance parameters

Assembly Code does not belong to the instance — it belongs to the type.

That’s why this rule works in two phases:


Phase 1 — filter and collect FamilySymbols

$symbols := $[type = "FamilySymbol" ...];

This defines scope:

“Which types are relevant for this rule?”


Phase 2 — index symbols by ID

$symIndex := $merge($symbols.{$string(id): $});

This creates a lookup table:

  • Key = FamilySymbol ID
  • Value = full FamilySymbol object

This avoids expensive repeated searches.


Phase 3 — enrich FamilyInstances

$sym := $lookup($symIndex, $string(parent.id));

Here’s the key concept:

A FamilyInstance references its type via parent.id

So now you can safely do:

$sym.values.assemblyCode
$sym.values.category.label

This is how type data flows into instance-level validation.


Important rule of thumb for users

This is the line you want to explicitly teach:

You must know where the data lives before you build your filter.

  • If the data is on the type, filter types first
  • If the data is on the instance, filter instances directly
  • If the data is on ProjectInfo / Parameter, resolve it separately

Guessing leads to broken rules.


Copy–paste is not cheating

Once a rule like this works:

✔ Symbol filtering ✔ Symbol indexing ✔ Instance enrichment ✔ Shared parameter extraction

Users should copy it and adapt:

  • Change the category logic
  • Change the Assembly Code regex
  • Change $paramGuids
  • Add or remove output fields

That is how consistent, maintainable rules are built.