Handling Instance and Type Parameters in Revit with JSONata
This document explains how to correctly retrieve shared parameters in Revit models when writing JSONata rules. In Revit, parameters may exist either on the FamilyInstance (Instance) or on the FamilySymbol (Type). A robust validation rule must therefore handle both cases.
JSONata Filter — Instance / Type Parameter Resolution
The following filter demonstrates a reusable pattern for retrieving parameters regardless of where they are stored.
(
/* =========================================================
1. Parameter GUID configuration
---------------------------------------------------------
Logical parameter names mapped to their GUIDs.
Using GUIDs avoids ambiguity because parameter names
in Revit are not guaranteed to be unique.
========================================================= */
$paramGuids := {
"Objecttype_Number": "104c3657-6918-4b2b-a0b9-bf4b05c8621a",
"Objecttype_Description": "2bc41923-4e29-4bf8-9911-992c87f16d26"
};
/* =========================================================
2. Parameter metadata cache
---------------------------------------------------------
Build a lookup table of parameter metadata once.
This avoids repeatedly searching for parameter definitions
and improves performance on large models.
========================================================= */
$paramMetaByGuid :=
$merge(
$[type = "Parameter" and values.guid in $paramGuids.*].{
$string(values.guid): {
"guid": values.guid,
"name": values.name
}
}
);
/* =========================================================
3. Shared parameter retrieval helper
---------------------------------------------------------
Retrieves a shared parameter from a given object.
The object can be:
- a FamilyInstance
- a FamilySymbol
Parameters in DAQS JSON are stored using the format:
values.p_<GUID>
========================================================= */
$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;
$present := $exists($sp);
{
"paramExist": $present,
"value": $present and $exists($sp.value) ? $sp.value : null,
"valueAsString": $present and $exists($sp.valueAsString) ? $sp.valueAsString : null,
"guid": $meta ? $meta.guid : $guid,
"name": $meta ? $meta.name : $logicalName
}
)
};
/* =========================================================
4. Effective parameter helper
---------------------------------------------------------
In Revit, parameters may be defined either on:
• FamilyInstance (Instance parameter)
• FamilySymbol (Type parameter)
In this project a parameter exists in only one location.
This helper retrieves the effective value regardless
of where the parameter is stored.
========================================================= */
$getEffectiveParam := function($instance, $symbol, $logicalName){
(
$inst := $getSharedParam($instance, $logicalName);
$inst.paramExist
? $inst
: $getSharedParam($symbol, $logicalName)
)
};
/* =========================================================
5. Symbol scope
---------------------------------------------------------
Select relevant FamilySymbols.
Limiting scope improves performance when processing
large models.
========================================================= */
$symbols :=
$[
type = "FamilySymbol"
and values.category.type = "Model"
];
/* =========================================================
6. Build symbol lookup index
---------------------------------------------------------
Create a fast lookup dictionary:
symbolId → symbol object
This allows instances to resolve their type quickly.
========================================================= */
$symIndex :=
$merge(
$symbols.{
$string(id): $
}
);
/* =========================================================
7. Main query — iterate over FamilyInstances
========================================================= */
$[
type = "FamilyInstance"
].(
$sym := $lookup($symIndex, $string(parent.id));
$sym ?
(
/* Retrieve parameters regardless of storage location */
$Objecttype_Number :=
$getEffectiveParam($, $sym, "Objecttype_Number");
$Objecttype_Description :=
$getEffectiveParam($, $sym, "Objecttype_Description");
{
"id": id,
"type": type,
"name": name,
"Category": $sym.values.category.label,
"assemblyCode": $sym.values.assemblyCode,
"Objecttype_Number": $Objecttype_Number,
"Objecttype_Description": $Objecttype_Description
}
)
: ()
)
)
The Problem
In Revit, parameters may be defined at two different levels:
| Level | Revit Object |
|---|---|
| Instance | FamilyInstance |
| Type | FamilySymbol |
A parameter defined on the Type automatically applies to all instances of that type.
However, many validation scripts only inspect FamilyInstances. When a parameter exists only on the FamilySymbol, the rule may incorrectly report that the parameter is missing.
Example Scenario
| Element | Type | Parameter Location |
|---|---|---|
| Light 1 | LightTypeA | Type |
| Light 2 | LightTypeA | Type |
If the validation checks only the instance:
values.p_GUID
the parameter appears missing even though it exists on the type.
The Effective Parameter Pattern
To correctly validate Revit data, rules should check:
Instance parameter
OR
Type parameter
The filter implements this using a helper function:
$getEffectiveParam($instance, $symbol, $logicalName)
Logic:
If instance parameter exists
use instance value
Else
use type value
This ensures the rule works regardless of where the parameter is stored.
Why GUIDs Are Used
Shared parameters are retrieved using GUIDs rather than names.
Reasons:
- Parameter names are not guaranteed to be unique
- Multiple parameters can share the same name
- GUIDs uniquely identify the parameter definition
Example configuration:
$paramGuids := {
"Objecttype_Number": "104c3657-6918-4b2b-a0b9-bf4b05c8621a",
"Objecttype_Description": "2bc41923-4e29-4bf8-9911-992c87f16d26"
};
Performance Considerations
Two optimizations are used.
Parameter Metadata Cache
Parameter definitions are retrieved once and stored in a lookup table:
GUID → Parameter metadata
This avoids repeated searches through all parameters.
Symbol Lookup Index
A lookup index is created for symbols:
symbolId → symbol
This allows instances to quickly resolve their type.
Result Structure
Each FamilyInstance in the output contains:
- instance id
- element name
- category
- assembly code
- resolved parameter values
Conceptually:
FamilyInstance
│
▼
Resolve FamilySymbol
│
▼
Retrieve effective parameter
Key Takeaway
Reliable Revit validation must handle both parameter locations:
Instance parameter
OR
Type parameter
This Instance/Type resolution pattern is a fundamental building block for most BIM validation rules.