Find Twins in the Digital Twin Registry
Twins can be queried at the /registry-api/v2/twins
endpoint. This endpoint supports filtering and paging in order to give the client control about how many and which resources it wants to retrieve.
Filtering reduces the amount of retrieved entities by given criteria, paging returns a subset of the results. With sorting, the retrieved results are returned in a predefined order.
Filtering
The Digital Twin Registry API supports filtering via RQL (Resource Query Language).
Filtering of results is specified by the value of the query parameter filter
.
The general form of the query string looks as follows:
If there is an issue processing the filter expression, the response will provide details on the error.
Operators
The value for {filter expression}
is an expression that uses one of the following operators.
-
Comparison operators:
-
eq
-
in
-
ne
-
gt
-
ge
-
lt
-
le
-
like
-
likeIgnoreCase
-
-
Logical operators:
-
and
-
or
-
not
-
The following examples illustrate how an RQL {filter expression}
could look like.
Return Twins that have a description
containing "my device":
likeIgnoreCase(description,"*my device*")
Return Twins that carry a label
named "A":
eq(labels.name,"A")
Return Twins of twinKind
"INSTANCE":
eq(twinKind,"INSTANCE")
Return Twins that have a twinCategory
of either "Machine" or "Device":
in(twinCategory,"Machine","Device")
Return Twins with a given twinCategory
and at least one label with name "Floor1":
and(eq(twinCategory,"Printer"), eq(labels.name,"Floor1"))
Supported attributes
Starting root | Attributes |
---|---|
Twin |
id, twinType, twinCategory, twinKind, description, aspects, localIdentifiers, labels, groups (are Digital Twin Groups - shortcut for groupMemberships.group) |
Local identifier |
id, digitalTwin, hash, valueSet, localIdentifierKeyPairs.<key> |
Label |
id, name, digitalTwin |
Digital Twin Group |
id, name |
Aspect |
id, modelReference, digitalTwin, httpEndpoints, mqttEndpoints |
Aspect Model reference |
urn |
Aspect HTTP endpoint |
id, aspect, twin |
Aspect MQTT endpoint |
id, aspect |
Aspect template |
id, name, modelReference, httpEndpointTemplates, mqttEndpointTemplates, groups (are Digital Twin Groups - shortcut for templateGroupMemberships.digitalTwinGroup) |
Model reference template |
id, urn |
HTTP endpoint template |
id, aspectTemplate |
MQTT endpoint template |
id, aspectTemplate |
Group statistic |
id |
Each RQL filtering expression displays which is the starting root.
The following attributes work with the respective operators:
Attributes | Operators |
---|---|
id |
All comparison operators except |
Label.name |
|
DigitalTwin.twinType, DigitalTwin.twinCategory, DigitalTwin.description, DigitalTwin.twinKind, LocalIdentifier.hash, LocalIdentifier.valueSet, LocalIdentifier,localIdentifierKeyPairs.<key>, Aspect.modelReference.urn, AspectTemplate.modelReference.urn |
All comparison operators ( |
Relation attributes — used to cascade from one starting root to another. They are named like the starting roots, to which they lead, e.g. aspect, twin, aspectTemplate. |
They do not work with operators on their own, but combined with attributes that do, they form queries that use the supported operators for those attributes. For example: Starting from aspect: Starting from digitalTwin: Starting from aspectTemplate: |
If additional attributes are required, please contact us at support.semantic-stack@bosch.com.
Paging
A number of API endpoints provide cursor pagination.
Cursor pagination
The cursor pagination methodology divides the entities of a larger dataset, based on various criteria.
-
This type of pagination is broadly intended for continuous pagination and therefore lacks the option to select a specific page index, in favor of basing the pagination on a specific cursor, provided by the back-end in the first response (assuming the dataset has more than one page).
-
In cursor pagination, once the client obtains the first page and a cursor for the next one, it can send the next request with that cursor as an argument, in order to fetch the next page.
-
Cursor pagination uses logarithmic solutions to scroll through a sorted dataset, which tends to perform increasingly better than offset pagination the larger the dataset and the closer to its end data is being fetched.
-
In other words, cursor pagination is preferable in the vast majority of use cases
One criterion to cursor pagination methodology is the size of the page, expressed as:
-
the
limit
argument expressed as a query parameter in non-bulk APIs using cursor pagination (e.g.,?limit=50
) -
the
limit
argument expressed in the request body for bulk APIs using cursor pagination (e.g.,"limit": 50
)
There is a small difference between the Digital Twin Registry API and the Bulk API:
-
the bulk API endpoints feature both offset and cursor pagination based on the request parametrization: if RQL
limit(x,y)
is used, offset pagination will be used - conversely, if thelimit
andcursor
arguments are used in the request body, cursor pagination will be used -
the non-bulk API endpoints featuring cursor pagination for the
v2
API
Finally, the page size defaults are featured similarly, but not identically for the two methodologies:
Operation type | Cursor-based | Default page size | Maximum page size |
---|---|---|---|
Bulk |
Yes |
Relevant bulk max quota for that endpoint |
Relevant bulk max quota for that endpoint |
Bulk |
No |
No default: desired page size must be specified in RQL |
Relevant bulk max quota for that endpoint |
Non-bulk |
Yes |
500 |
500 |
-
In all cases, when a desired page size exceeds the maximum page size or quota, the request will fail with an error
-
For specific information about the bulk API quotas, please refer to the API documentation
Cursor pagination interaction lifecycle
This section summarizes the typical exchanges between client and server when cursor pagination is involved. The two small sections above underline the similarities and small differences between bulk and non-bulk APIs in that process.
Bulk APIs
-
The client requests data via a cursor-paginating endpoint, optionally parameterizing the request with:
-
a `limit` within the supported bulk quota (defaults to `500` elements if absent)
-
an RQL
filter
query (defaults to "all elements of that type" if absent)
-
-
The server responds with the first page of elements.
-
If more elements are present in the dataset, the response body will contain a
nextCursor
value, expressed as a string.
-
-
If the server response contains a
nextCursor
value, the client copies it ascursor
in the query parameters of the next request -
In turn, the server provides a page of elements after that
cursor
, and again thenextCursor
value in the next response, if any more pages are available. -
This exchange iterates ad lib. until the server stops providing a
nextCursor
value in the response. -
Once no
nextCursor
value is available to the client, it "knows" it has reached the end of the desired dataset, and can stop sending further requests.
Non-bulk APIs
-
The client requests data via a cursor-paginating endpoint, optionally parameterizing the request with:
-
a
limit
value up to, and defaulting to500
elements -
an RQL
filter
query (defaults to "all elements of that type" if absent)
-
-
The server responds with the first page of elements.
-
If more elements are present in the dataset, the response body will contain a
nextCursor
value, expressed as a string.
-
-
If the server response contains a
nextCursor
value, the client copies it ascursor
in the query parameters of the next request -
In turn, the server provides a page of elements after that
cursor
, and again thenextCursor
value in the next response, if any more pages are available. -
This exchange iterates ad lib. until the server stops providing a
nextCursor
value in the response. -
Once no
nextCursor
value is available to the client, it "knows" it has reached the end of the desired dataset, and can stop sending further requests.
Sorting
With user-defined sorting, the client is responsible for preventing an arbitrary order of the retrieved results.
User-defined sorting can be achieved by using the RQL options operator with the keyword sort
.
Two different use cases exist:
-
Use case 1: The client provides sorting information via the
sort
keyword.-
Example:
option=sort(-id)
-
Sort direction for a property can be given with:
-
+
for ascending order -
-
for descending order
-
-
-
Use case 2: The client does not provide any sorting information.
-
The results will be sorted by default sorting.
-
Default sorting happens by ID and in ascending order, which implicitly also yields an ascending order by creation time.
-
If sorting is used with a cursor, the sort expression must NOT change from the previous request. Otherwise incorrect results or an error may occur. |
Note that:
-
User-defined sorting may result in longer response times.
-
Even if the client provides sorting information, arbitrary ordering can still occur if parallel accesses (deleting or adding elements) take place.
-
If it is important that all elements are returned, user-defined sorting cannot be used.
Currently, only reviewed attributes from the root entity can be used. If a desired attribute is not available, please contact us.
Select
The select operator trims each response down to the set of attributes defined in the arguments of the query. User-defined select can be requested via RQL for a root entity. All child entities will then not be loaded.
This means that response times can be significantly improved if only the requested information is returned.
Example:
Load only twin IDs (select) and do that only for twins that have the label blue
assigned (filter).
select=id&filter=eq(labels.name, "blue")