Material Filters

Material

(
  $categories := ["Profiles","Supports","Detail Items"];
  $familyIds := $[type = "Family"].id;

  $[
    type = "FamilySymbol"
    and parent.id in $familyIds
    and $not(values.category.name in $categories)
    and $exists(values.solids.allFacesHaveMaterial)
    and values.solids.allFacesHaveMaterial != null
  ].{
    "id": id,
    "type": type,
    "name": name,
    "allFacesHaveMaterial":
      $not(false in ($type(values.solids.allFacesHaveMaterial) = "array"
                     ? values.solids.allFacesHaveMaterial
                     : [values.solids.allFacesHaveMaterial]))
  }
)

All Materials

(
  /* 1) collect ids of all MaterialId parameters */
  $matParamIds := $$[type = "Parameter" and values.spec = "MaterialId"].id;

  /* 2) keys in an object that start with p_ */
  $getPKeys := function($values){
    $filter($keys($values), function($k){ $match($k, /^p_/) })
  };

  /* 3) only the p_* keys that are MaterialId parameters */
  $getMaterialSPKeys := function($values){
    $filter(
      $getPKeys($values),
      function($k){
        $exists($lookup($values,$k)) and
        $lookup($values,$k).ref = "Parameter" and
        ($count($matParamIds[$ = $lookup($values,$k).id]) > 0)
      }
    )
  };

    /* Returns a single name for a single id, or an array of names for an array of ids */
    $nameById := function($id){
      ($type($id) = "array")
      ? $map($id, function($i){ ($$[id = $i])[0].name })
      : ($$[id = $id])[0].name
    };


  /* 5) details for those keys (adds valueName by id-lookup) */
  $getMaterialSPDetails := function($values){
    $map(
      $getMaterialSPKeys($values),
      function($k){
        {
          "key": $k,
          "paramId": $lookup($values,$k).id,
          "value": $lookup($values,$k).value,
          "valueAsString": $lookup($values,$k).valueAsString,
          "valueName": $nameById($lookup($values,$k).value)
        }
      }
    )
  };

  /* 6) helper: get a FamilySymbol's values by id */
  $symbolValues := function($symbolId){
    ($$[type = "FamilySymbol" and id = $symbolId])[0].values
  };

  /* RESULT: only FamilyInstances with MaterialId SPs (self or parent) */
  $[
    type = "FamilyInstance" and
    (
      $count($getMaterialSPKeys(values)) > 0 or
      $count($getMaterialSPKeys($symbolValues(parent.id))) > 0
    )
  ].{
    "id": id,
    "name": name,
    "parentId": parent.id,
    "parentName": ($$[type = "FamilySymbol" and id = parent.id])[0].name,
    "materialNames":$nameById(values.materialIds),

    /* instance structural material + name */
    "instance_structuralMaterialId": values.structuralMaterialId,
    "instance_structuralMaterialName": $nameById(values.structuralMaterialId),

    /* parent symbol structural material + name */
    "symbol_structuralMaterialId": $symbolValues(parent.id).structuralMaterialId,
    "symbol_structuralMaterialName": $nameById($symbolValues(parent.id).structuralMaterialId),

    /* combined details (tag source) */
    "materialSP_details": $append(
      $map($getMaterialSPDetails(values), function($d){ $merge([$d, {"source":"instance"}]) }),
      $map($getMaterialSPDetails($symbolValues(parent.id)), function($d){ $merge([$d, {"source":"symbol"}]) })
    )
  }
)

all Material parameters

(
  /* 1) collect ids of all MaterialId parameters */
  $matParamIds := $$[type = "Parameter" and values.spec = "MaterialId"].id;

  /* 2) keys in an object that start with p_ */
  $getPKeys := function($values){
    $filter($keys($values), function($k){ $match($k, /^p_/) })
  };

  /* 3) only the p_* keys that are MaterialId parameters */
  $getMaterialSPKeys := function($values){
    $filter(
      $getPKeys($values),
      function($k){
        $exists($lookup($values,$k)) and
        $lookup($values,$k).ref = "Parameter" and
        ($count($matParamIds[$ = $lookup($values,$k).id]) > 0)
      }
    )
  };

    /* 4 Returns a single name for a single id, or an array of names for an array of ids */
    $nameById := function($id){
      ($type($id) = "array")
      ? $map($id, function($i){ ($$[id = $i])[0].name })
      : ($$[id = $id])[0].name
    };

    /* 4a Returns a single name for a single id, or an array of names for an array of ids */
    $nameArrayById := function($ids){
      $filter(
        $map( ($type($ids) = "array") ? $ids : [$ids],
              function($i){ ($$[id = $i])[0].name } ),
        function($n){ $exists($n) }
      )
    };


  /* 5) details for those keys (adds valueName by id-lookup) */
  $getMaterialSPDetails := function($values){
    $map(
      $getMaterialSPKeys($values),
      function($k){
        {
          "key": $k,
          "paramId": $lookup($values,$k).id,
          "value": $lookup($values,$k).value,
          "valueAsString": $lookup($values,$k).valueAsString,
          "valueName": $nameById($lookup($values,$k).value)
        }
      }
    )
  };

  /* 6) helper: get a FamilySymbol's values by id */
  $symbolValues := function($symbolId){
    ($$[type = "FamilySymbol" and id = $symbolId])[0].values
  };

  /* RESULT: only FamilyInstances with MaterialId SPs (self or parent) */
  $[
    type = "FamilyInstance" and
    (
      $count($getMaterialSPKeys(values)) > 0 or
      $count($getMaterialSPKeys($symbolValues(parent.id))) > 0
    )
  ].{
    "id": id,
    "name": name,
    "parentId": parent.id,
    "parentName": ($$[type = "FamilySymbol" and id = parent.id])[0].name,
    "materialNames":$count($nameArrayById(values.materialIds))> 0 ? $nameArrayById(values.materialIds):"",

    /* instance structural material + name */
    "instance_structuralMaterialId": values.structuralMaterialId,
    "instance_structuralMaterialName": $exists($nameById(values.structuralMaterialId))?$nameById(values.structuralMaterialId):"",

    /* parent symbol structural material + name */
    "symbol_structuralMaterialId": $symbolValues(parent.id).structuralMaterialId,
    "symbol_structuralMaterialName": $exists($nameById($symbolValues(parent.id).structuralMaterialId))?$nameById($symbolValues(parent.id).structuralMaterialId):"",

    /* combined details (tag source) */
    "materialSP_details": $append(
      $map($getMaterialSPDetails(values), function($d){ $merge([$d, {"source":"instance"}]) }),
      $map($getMaterialSPDetails($symbolValues(parent.id)), function($d){ $merge([$d, {"source":"symbol"}]) })
    )
  }
)

example

```JSONata (

/* Drop null/empty, then dedupe */
$cleanDistinct := function($arr){
  $distinct(
    $filter($arr, function($n){
      $exists($n) and $type($n) = "string" and $trim($n) != ""
      /* Optional: also drop placeholders like "{$ElementID}" */
      /* and not $match($n, /^\{\$.*\}$/) */
    })
  )
};

/ Collect ids of all MaterialId parameters / $matParamIds := $$[type = "Parameter" and values.spec = "MaterialId"].id;

/ p_ keys in an object */ $getPKeys := function($values){ $filter($keys($values), function($k){ $match($k, /^p_/) }) };

/ p_ keys that are MaterialId parameters */ $getMaterialSPKeys := function($values){ $filter( $getPKeys($values), function($k){ $exists($lookup($values,$k)) and $lookup($values,$k).ref = "Parameter" and ($count($matParamIds[$ = $lookup($values,$k).id]) > 0) } ) };

/ Always return array of names for id(s) (skip nulls) / $nameArrayById := function($ids){ $filter( $map( ($type($ids) = "array") ? $ids : ($exists($ids) ? [$ids] : []), function($i){ ($$[id = $i])[0].name } ), function($n){ $exists($n) } ) };

/ Details for MaterialId SP keys / $getMaterialSPDetails := function($values){ $map( $getMaterialSPKeys($values), function($k){ { "key": $k, "paramId": $lookup($values,$k).id, "value": $lookup($values,$k).value, "valueAsString": $lookup($values,$k).valueAsString, "valueName": $nameArrayById($lookup($values,$k).value)[0] } } ) };

/ NEW: names from SPs using valueAsString / $getMatNamesFromSPStrings := function($values){ $filter( $map($getMaterialSPKeys($values), function($k){ $lookup($values,$k).valueAsString }), function($s){ $exists($s) and $s != "" } ) };

/ Parent symbol helpers / $symbolValues := function($symbolId){ ($$[type = "FamilySymbol" and id = $symbolId])[0].values }; $ensureObj := function($x){ ($type($x) = "object") ? $x : {} };

/ Concat arrays, then dedupe / $concat := function($arrs){ $reduce($arrs, function($a,$b){ $append($a,$b) }, []) };

/* Collect all material names (instance + symbol) incl. SP.valueAsString */
$collectAllMaterialNames := function($instVals, $symVals){
  $cleanDistinct(
    $concat([
      $nameArrayById($instVals.materialIds),
      $nameArrayById($symVals.materialIds),
      $nameArrayById($instVals.structuralMaterialId),
      $nameArrayById($symVals.structuralMaterialId),
      $nameArrayById($map($getMaterialSPKeys($instVals), function($k){ $lookup($instVals,$k).value })),
      $nameArrayById($map($getMaterialSPKeys($symVals),  function($k){ $lookup($symVals,$k).value })),
      $getMatNamesFromSPStrings($instVals),
      $getMatNamesFromSPStrings($symVals)
    ])
  )
};

/ RESULT / $[ type = "FamilyInstance" and ( $count($getMaterialSPKeys(values)) > 0 or $count($getMaterialSPKeys($ensureObj($symbolValues(parent.id)))) > 0 ) ].{ "id": id, "name": name, "parentId": parent.id, "parentName": ($$[type = "FamilySymbol" and id = parent.id])[0].name,

/* Single, de-duplicated list incl. SP.valueAsString */
"allMaterialNames": $join($collectAllMaterialNames(values, $ensureObj($symbolValues(parent.id))),", "),

/* Keep details if you like */
"materialSP_details": $append(
  $map($getMaterialSPDetails(values), function($d){ $merge([$d, {"source":"instance"}]) }),
  $map($getMaterialSPDetails($ensureObj($symbolValues(parent.id))), function($d){ $merge([$d, {"source":"symbol"}]) })
)

} )```

```jsonata ( / Drop null/empty, then dedupe / $cleanDistinct := function($arr){ $distinct( $filter($arr, function($n){ $exists($n) and $type($n) = "string" and $trim($n) != "" / Optional: also drop placeholders like "{$ElementID}" / / and not $match($n, /^{\$.}$/) / }) ) }; / Collect ids of all MaterialId parameters */ $matParamIds := $$[type = "Parameter" and values.spec = "MaterialId"].id;

/ p_ keys in an object */ $getPKeys := function($values){ $filter($keys($values), function($k){ $match($k, /^p_/) }) };

/ p_ keys that are MaterialId parameters */ $getMaterialSPKeys := function($values){ $filter( $getPKeys($values), function($k){ $exists($lookup($values,$k)) and $lookup($values,$k).ref = "Parameter" and ($count($matParamIds[$ = $lookup($values,$k).id]) > 0) } ) };

/ Always return array of names for id(s) (skip nulls) / $nameArrayById := function($ids){ $filter( $map( ($type($ids) = "array") ? $ids : ($exists($ids) ? [$ids] : []), function($i){ ($$[id = $i])[0].name } ), function($n){ $exists($n) } ) };

/ Details for MaterialId SP keys / $getMaterialSPDetails := function($values){ $map( $getMaterialSPKeys($values), function($k){ { "key": $k, "paramId": $lookup($values,$k).id, "value": $lookup($values,$k).value, "valueAsString": $lookup($values,$k).valueAsString, "valueName": $nameArrayById($lookup($values,$k).value)[0] } } ) };

/ NEW: names from SPs using valueAsString / $getMatNamesFromSPStrings := function($values){ $filter( $map($getMaterialSPKeys($values), function($k){ $lookup($values,$k).valueAsString }), function($s){ $exists($s) and $s != "" } ) };

/ Parent symbol helpers / $symbolValues := function($symbolId){ ($$[type = "FamilySymbol" and id = $symbolId])[0].values }; $ensureObj := function($x){ ($type($x) = "object") ? $x : {} };

/ Concat arrays, then dedupe / $concat := function($arrs){ $reduce($arrs, function($a,$b){ $append($a,$b) }, []) };

/* Collect all material names (instance + symbol) incl. SP.valueAsString */
$collectAllMaterialNames := function($instVals, $symVals){
  $cleanDistinct(
    $concat([
      $nameArrayById($instVals.materialIds),
      $nameArrayById($symVals.materialIds),
      $nameArrayById($instVals.structuralMaterialId),
      $nameArrayById($symVals.structuralMaterialId),
      $nameArrayById($map($getMaterialSPKeys($instVals), function($k){ $lookup($instVals,$k).value })),
      $nameArrayById($map($getMaterialSPKeys($symVals),  function($k){ $lookup($symVals,$k).value })),
      $getMatNamesFromSPStrings($instVals),
      $getMatNamesFromSPStrings($symVals)
    ])
  )
};

/ RESULT / $[ type = "FamilyInstance" and ( $count($getMaterialSPKeys(values)) > 0 or $count($getMaterialSPKeys($ensureObj($symbolValues(parent.id)))) > 0 ) ].{ "id": id, "name": name, "parentId": parent.id, "parentName": ($$[type = "FamilySymbol" and id = parent.id])[0].name, "allMaterialNames": $count($collectAllMaterialNames(values, $ensureObj($symbolValues(parent.id)),", "))>0?$join($collectAllMaterialNames(values, $ensureObj($symbolValues(parent.id))),", "):"", "allMaterialNamesNum": $count($collectAllMaterialNames(values, $ensureObj($symbolValues(parent.id))),), } ) ````