This guide shows concrete query and ABAC filter inputs together with the expected result. For the expression grammar and SQL translation details, see the query language architecture guide.
| Endpoint | Main field roots | Typical content |
|---|---|---|
POST /query/shells |
$aas |
Asset Administration Shells |
POST /query/submodels |
$sm, $sme |
Submodels and their elements |
POST /query/shell-descriptors |
$aasdesc, nested $smdesc |
AAS Descriptors and nested Submodel Descriptors |
POST /query/submodel-descriptors |
$smdesc |
Submodel Descriptors |
Every request requires a top-level $condition. It selects the parent objects
in result. Optional $filters shape fragments inside those objects. Available
field paths depend on the endpoint's model and reader.
$match in a request and MATCH in an ABAC rule are not separate predicates.
They only change whether their enclosing fragment condition is evaluated at
parent scope or against the current fragment row.
Each example shows the complete expected response for the displayed starting
object, including paging_metadata, the parent object, unchanged displayed
fields, and the filtered fragments. The starting objects intentionally contain
only the fields needed to demonstrate the behavior.
Starting data:
[
{ "id": "urn:sm:motor", "idShort": "Motor" },
{ "id": "urn:sm:pump", "idShort": "Pump" }
]Request:
POST /query/submodels
Content-Type: application/json{
"$condition": {
"$eq": [
{ "$field": "$sm#idShort" },
{ "$strVal": "Motor" }
]
}
}Expected result:
{
"paging_metadata": {},
"result": [
{ "id": "urn:sm:motor", "idShort": "Motor" }
]
}The top-level condition removes the Pump parent from result. It does not
mask individual fragments inside Motor.
Starting Submodel:
{
"id": "urn:sm:motor",
"idShort": "Motor",
"supplementalSemanticIds": [
{
"type": "ExternalReference",
"keys": [{ "type": "GlobalReference", "value": "VISIBLE" }]
},
{
"type": "ExternalReference",
"keys": [{ "type": "GlobalReference", "value": "INTERNAL" }]
}
]
}Request with $match omitted:
{
"$condition": {
"$eq": [
{ "$field": "$sm#id" },
{ "$strVal": "urn:sm:motor" }
]
},
"$filters": [
{
"$fragment": "$sm#supplementalSemanticIds[]",
"$condition": {
"$eq": [
{ "$field": "$sm#supplementalSemanticIds[].keys[].value" },
{ "$strVal": "VISIBLE" }
]
}
}
]
}Expected result:
{
"paging_metadata": {},
"result": [
{
"id": "urn:sm:motor",
"idShort": "Motor",
"supplementalSemanticIds": [
{
"type": "ExternalReference",
"keys": [{ "type": "GlobalReference", "value": "VISIBLE" }]
},
{
"type": "ExternalReference",
"keys": [{ "type": "GlobalReference", "value": "INTERNAL" }]
}
]
}
]
}The condition is evaluated at parent scope. Because one reference contains
VISIBLE, the complete fragment is preserved. Setting $match to false has
the same effect.
Use the same starting data as example 2, but explicitly set $match:
{
"$condition": {
"$eq": [
{ "$field": "$sm#id" },
{ "$strVal": "urn:sm:motor" }
]
},
"$filters": [
{
"$fragment": "$sm#supplementalSemanticIds[]",
"$match": true,
"$condition": {
"$eq": [
{ "$field": "$sm#supplementalSemanticIds[].keys[].value" },
{ "$strVal": "VISIBLE" }
]
}
}
]
}Expected result:
{
"paging_metadata": {},
"result": [
{
"id": "urn:sm:motor",
"idShort": "Motor",
"supplementalSemanticIds": [
{
"type": "ExternalReference",
"keys": [{ "type": "GlobalReference", "value": "VISIBLE" }]
}
]
}
]
}$match: true binds the condition to the reference currently being
reconstructed, so the INTERNAL sibling is removed.
Starting structure, shortened to the relevant fields:
{
"id": "urn:sm:nested",
"submodelElements": [
{
"idShort": "a",
"modelType": "SubmodelElementList",
"value": [
{
"modelType": "SubmodelElementCollection",
"value": [
{
"idShort": "b",
"modelType": "SubmodelElementList",
"value": [
{ "modelType": "Property", "value": "a0-b0" },
{ "modelType": "Property", "value": "a0-b1" }
]
}
]
},
{
"modelType": "SubmodelElementCollection",
"value": [
{
"idShort": "b",
"modelType": "SubmodelElementList",
"value": [
{ "modelType": "Property", "value": "a1-b0" },
{ "modelType": "Property", "value": "a1-b1" }
]
}
]
}
]
}
]
}Request:
{
"$condition": {
"$eq": [
{ "$field": "$sm#id" },
{ "$strVal": "urn:sm:nested" }
]
},
"$filters": [
{
"$fragment": "$sme.a[].b[]",
"$match": true,
"$condition": {
"$ends-with": [
{ "$field": "$sme.a[].b[]#value" },
{ "$strVal": "-b0" }
]
}
}
]
}Expected result:
{
"paging_metadata": {},
"result": [
{
"id": "urn:sm:nested",
"submodelElements": [
{
"idShort": "a",
"modelType": "SubmodelElementList",
"value": [
{
"modelType": "SubmodelElementCollection",
"value": [
{
"idShort": "b",
"modelType": "SubmodelElementList",
"value": [
{ "modelType": "Property", "value": "a0-b0" }
]
}
]
},
{
"modelType": "SubmodelElementCollection",
"value": [
{
"idShort": "b",
"modelType": "SubmodelElementList",
"value": [
{ "modelType": "Property", "value": "a1-b0" }
]
}
]
}
]
}
]
}
]
}The outer a[] structure is unchanged. Inside a[0], a0-b0 remains and
a0-b1 is removed. Inside a[1], a1-b0 remains and a1-b1 is removed.
Each [] is bound to the current numeric list index, so values from a[0]
cannot satisfy the condition for a[1].
An indexed fragment can target only one branch. Full request:
{
"$condition": {
"$eq": [
{ "$field": "$sm#id" },
{ "$strVal": "urn:sm:nested" }
]
},
"$filters": [
{
"$fragment": "$sme.a[1].b[]",
"$match": true,
"$condition": {
"$ends-with": [
{ "$field": "$sme.a[].b[]#value" },
{ "$strVal": "-b0" }
]
}
}
]
}Expected result:
{
"paging_metadata": {},
"result": [
{
"id": "urn:sm:nested",
"submodelElements": [
{
"idShort": "a",
"modelType": "SubmodelElementList",
"value": [
{
"modelType": "SubmodelElementCollection",
"value": [
{
"idShort": "b",
"modelType": "SubmodelElementList",
"value": [
{ "modelType": "Property", "value": "a0-b0" },
{ "modelType": "Property", "value": "a0-b1" }
]
}
]
},
{
"modelType": "SubmodelElementCollection",
"value": [
{
"idShort": "b",
"modelType": "SubmodelElementList",
"value": [
{ "modelType": "Property", "value": "a1-b0" }
]
}
]
}
]
}
]
}
]
}a[0].b remains complete, while only a[1].b is filtered.
A Submodel Descriptor can filter endpoints and supplemental semantic IDs in the same request. Starting descriptor:
{
"id": "urn:smdesc:motor",
"endpoints": [
{
"interface": "SUBMODEL-3.0",
"protocolInformation": { "href": "https://public.example/motor" }
},
{
"interface": "SUBMODEL-2.0",
"protocolInformation": { "href": "https://legacy.example/motor" }
}
],
"supplementalSemanticIds": [
{
"type": "ExternalReference",
"keys": [{ "type": "GlobalReference", "value": "PUBLIC" }]
},
{
"type": "ExternalReference",
"keys": [{ "type": "GlobalReference", "value": "INTERNAL" }]
}
]
}Request:
{
"$condition": {
"$eq": [
{ "$field": "$smdesc#id" },
{ "$strVal": "urn:smdesc:motor" }
]
},
"$filters": [
{
"$fragment": "$smdesc#endpoints[]",
"$match": true,
"$condition": {
"$eq": [
{ "$field": "$smdesc#endpoints[].interface" },
{ "$strVal": "SUBMODEL-3.0" }
]
}
},
{
"$fragment": "$smdesc#supplementalSemanticIds[]",
"$match": true,
"$condition": {
"$eq": [
{ "$field": "$smdesc#supplementalSemanticIds[].keys[].value" },
{ "$strVal": "PUBLIC" }
]
}
}
]
}Expected result:
{
"paging_metadata": {},
"result": [
{
"id": "urn:smdesc:motor",
"endpoints": [
{
"interface": "SUBMODEL-3.0",
"protocolInformation": { "href": "https://public.example/motor" }
}
],
"supplementalSemanticIds": [
{
"type": "ExternalReference",
"keys": [{ "type": "GlobalReference", "value": "PUBLIC" }]
}
]
}
]
}Result explanation:
- Only endpoints with interface
SUBMODEL-3.0remain. - Only supplemental semantic references containing
PUBLICremain. - Other descriptor fields are unchanged.
- The two fragment conditions do not have to be satisfied by the same database row because they target different fragments.
Assume a descriptor contains:
{
"id": "urn:aasdesc:motor",
"specificAssetIds": [
{ "name": "customerPartId", "value": "P-100" },
{ "name": "customerPartId", "value": "P-200" },
{ "name": "manufacturerAssetId", "value": "M-9" }
]
}The relevant part of an allowing ABAC rule requires customer part IDs:
{
"USEACL": "reader",
"USEOBJECTS": ["query_routes"],
"USEFORMULA": "always_true",
"FILTER": {
"FRAGMENT": "$aasdesc#specificAssetIds[]",
"MATCH": true,
"CONDITION": {
"$eq": [
{ "$field": "$aasdesc#specificAssetIds[].name" },
{ "$strVal": "customerPartId" }
]
}
}
}The caller further narrows the same fragment:
{
"$condition": { "$boolean": true },
"$filters": [
{
"$fragment": "$aasdesc#specificAssetIds[]",
"$match": true,
"$condition": {
"$eq": [
{ "$field": "$aasdesc#specificAssetIds[].value" },
{ "$strVal": "P-100" }
]
}
}
]
}Effective fragment condition:
name = "customerPartId" AND value = "P-100"
Expected result:
{
"paging_metadata": {},
"result": [
{
"id": "urn:aasdesc:motor",
"specificAssetIds": [
{ "name": "customerPartId", "value": "P-100" }
]
}
]
}The request cannot expose manufacturerAssetId, because the ABAC filter is
mandatory. It also cannot recover P-200, because the request itself narrowed
the policy-visible rows to P-100.
$and,$or, and$notcan combine logical expressions.- Comparison operators such as
$eq,$ne,$gt,$ge,$lt, and$lecompare fields and values. - String operators such as
$contains,$starts-with,$ends-with, and$regexcan be used in conditions. - Multiple request filters can target the same fragment; they are combined with
AND. - Filters for different fragments are evaluated independently.
- Multiple permitting ABAC rules form
ORalternatives. A request query is applied after those alternatives and cannot widen them. - Each individual predicate retains its own
$matchorMATCHmode when these expressions are combined.
For exact value types, casts, field identifier syntax, and fragment guards, see the main query language guide.