Zum Inhalt springen

Business-Objekte und Knoten durchsuchen

Die RealityConnect API stellt zwei Such-Routen mit unterschiedlichem Umfang bereit: Die Business-Objekt-Suche durchsucht innerhalb eines Twins POIs, Zonen, Assets und deren Metadaten, während die Knotensuche die Knotenhierarchie Ihrer Organisation (Sites, Ordner, Twins und Dateien) durchsucht. Beide Routen sind experimentell und können sich ändern.


MethodePfadScopeZweck
GET/v1/twin/{contextId}/searchBasicBusiness-Objekte und Metadaten innerhalb eines Twins durchsuchen
GET/v1/nodes/searchReadHierarchyDie Knotenhierarchie der Organisation durchsuchen

GET /v1/twin/{contextId}/search durchsucht POIs, Zonen, Box-Assets, Messungen und andere Business-Objekte innerhalb eines einzelnen Twins (oder einer seiner Sites/Entwürfe, identifiziert durch contextId) und trifft dabei auf Name, reservierte Felder, Asset-Metadaten und objektspezifische Eigenschaften.

ParameterTypHinweise
fieldFiltersArray von JSON-ObjektenFilter mit reservierten Schlüsseln. Siehe unten.
metadataFiltersArray von JSON-ObjektenGleicht Asset-Metadateneigenschaften des Twins ab. Siehe unten.
additionalPropertyFiltersArray von JSON-ObjektenGleicht objekttypspezifische Eigenschaften ab (z. B. das icon eines POI). Siehe unten.
pageGanzzahlPositiv, Standard 1.
limitGanzzahl150, Standard 50.
searchNameQueryStringEigener Namensfilter, unabhängig vom name in fieldFilters.
nameMatchexact | containsAbgleichsmodus für searchNameQuery. Standard contains.
createdByIdUUIDFilter nach Ersteller.
createdBefore / createdAfterZeitstempelStreng davor/danach. Format YYYY-MM-DDTHH:mm:ss (kein Zeitzonen-Offset, keine Millisekunden).
updatedBefore / updatedAfterZeitstempelGleiches Format.
sortByname | createdAt | updatedAtSortierfeld.
sortDirASC | DESCSortierrichtung.

fieldFilters, metadataFilters und additionalPropertyFilters werden jeweils als ein JSON-Objekt-String pro Filter gesendet, für mehrere Filter wird der Query-Parameter wiederholt:

?fieldFilters={"key":"type","values":["poi"]}&fieldFilters={"key":"type","values":["zone"]}

Jedes Filterobjekt hat die Form { "key": string, "values": string[] }. Mehrere Werte im values-Array eines Filters werden mit ODER verknüpft.

fieldFilters akzeptiert nur diese reservierten Schlüssel — jeder andere Schlüssel wird stillschweigend ignoriert:

SchlüsselTrifft auf
typeBusiness-Objekttyp. Akzeptiert entweder den Enum-Wert (Poi, Zone, BoxAsset, CubePrimitive, PlanePrimitive, DistanceMeasure, CoordinateMeasure, DiameterMeasure, SurfaceMeasure, OrthogonalMeasure, Cut, ModelAsset) oder dessen normalisiertes Kebab-Case-Token — eine mit Bindestrichen versehene, kleingeschriebene Version des PascalCase-Namens, z. B. BoxAssetbox-asset.
asset-typeDer Asset-Typ des Objekts (wird auf assetTypeId abgebildet). Exakter Abgleich.
namePräfixabgleich nur auf den Namen, ohne Unschärfe.
idExakter Abgleich der Objekt-ID.

fieldFilters-Werte sind immer einfache Strings oder Enum-Tokens — die unten beschriebene Numerik-/Bereichs-Syntax gilt hier nicht.

metadataFilters und additionalPropertyFilters adressieren per Schlüssel eine schema-definierte Metadateneigenschaft (metadataFilters) oder eine objekttypspezifische Eigenschaft, die nicht Teil der gemeinsamen Metadaten ist (additionalPropertyFilters, z. B. das icon eines POI). Jeder Wert in values unterstützt:

Wert-SyntaxBedeutung
Einfacher StringExakter Abgleich. Mehrere einfache Strings in values werden mit ODER verknüpft.
* oder leerer StringWird übersprungen — ist er der einzige Wert, trifft der Filter allein auf das Vorhandensein des Schlüssels.
=123, !=123, >123, >=123, <123, <=123Numerischer Vergleich. Ganzzahlen, Dezimalzahlen und wissenschaftliche Notation (z. B. 1.5e+35) werden unterstützt.
range:[1..10]Inklusiver Zahlenbereich.
range:(1..10)Exklusiver Zahlenbereich.
range:[1..10) / range:(1..10]Gemischte inklusive/exklusive Grenzen.
true / falseNur additionalPropertyFilters — gleicht eine boolesche Eigenschaft direkt ab.

fieldFilters, metadataFilters und additionalPropertyFilters werden mit UND-Semantik kombiniert: Ein Ergebnis muss jeden einzelnen Filter erfüllen. Innerhalb eines einzelnen Filters werden die Werte im values-Array mit ODER verknüpft — zwei fieldFilters-Objekte mit demselben key verhalten sich also wie „einer der beiden Werte trifft zu”, während Filter auf unterschiedliche Schlüssel (oder unterschiedliche Filter-Arrays) die Ergebnismenge jeweils weiter einschränken.

Typfilter kombiniert mit einem numerischen Metadatenbereich (POIs mit einem erfassten Inspektionsdruck zwischen 80 und 120):

GET {api_url}/v1/twin/{contextId}/search?fieldFilters=%7B%22key%22%3A%22type%22%2C%22values%22%3A%5B%22poi%22%5D%7D&metadataFilters=%7B%22key%22%3A%22inspection.pressure%22%2C%22values%22%3A%5B%22range%3A%5B80..120%5D%22%5D%7D
Authorization: Bearer {access_token}

Asset-Typ kombiniert mit einem Namensfilter, neueste Aktualisierungen zuerst:

GET {api_url}/v1/twin/{contextId}/search?fieldFilters=%7B%22key%22%3A%22asset-type%22%2C%22values%22%3A%5B%22pump%22%5D%7D&fieldFilters=%7B%22key%22%3A%22name%22%2C%22values%22%3A%5B%22vibration%22%5D%7D&sortBy=updatedAt&sortDir=DESC
Authorization: Bearer {access_token}

Das bedeutet: Objekte, deren Asset-Typ pump ist und deren Name mit „vibration” beginnt, sortiert nach der zuletzt aktualisierten Reihenfolge.

Zwei fieldFilters auf demselben Schlüssel (ODER-verknüpft) kombiniert mit einem fieldFilters auf einem anderen Schlüssel (UND-verknüpft) — POIs oder Zonen, eingeschränkt auf den Asset-Typ pump:

GET {api_url}/v1/twin/{contextId}/search?fieldFilters=%7B%22key%22%3A%22type%22%2C%22values%22%3A%5B%22poi%22%2C%22zone%22%5D%7D&fieldFilters=%7B%22key%22%3A%22asset-type%22%2C%22values%22%3A%5B%22pump%22%5D%7D
Authorization: Bearer {access_token}

Ein boolesches additionalPropertyFilters-Literal kombiniert mit einem String-Abgleich in metadataFilters — aktive POIs, deren icon-nahe Metadaten einen „warning”-Status verzeichnen:

GET {api_url}/v1/twin/{contextId}/search?fieldFilters=%7B%22key%22%3A%22type%22%2C%22values%22%3A%5B%22poi%22%5D%7D&additionalPropertyFilters=%7B%22key%22%3A%22isActive%22%2C%22values%22%3A%5B%22true%22%5D%7D&metadataFilters=%7B%22key%22%3A%22inspection.status%22%2C%22values%22%3A%5B%22warning%22%5D%7D
Authorization: Bearer {access_token}

Eine vollständig ausgereizte Anfrage, die alle drei Filtereingaben, einen eigenen Namensfilter, einen Datumsbereich, Paginierung und Sortierung kombiniert — sie zeigt die vollständige Form einer Anfrage:

GET {api_url}/v1/twin/{contextId}/search?fieldFilters=%7B%22key%22%3A%22type%22%2C%22values%22%3A%5B%22poi%22%2C%22zone%22%5D%7D&metadataFilters=%7B%22key%22%3A%22inspection.pressure%22%2C%22values%22%3A%5B%22range%3A%5B80..120%5D%22%5D%7D&additionalPropertyFilters=%7B%22key%22%3A%22isActive%22%2C%22values%22%3A%5B%22true%22%5D%7D&searchNameQuery=Pump&nameMatch=contains&updatedAfter=2026-01-01T00%3A00%3A00&updatedBefore=2026-12-31T23%3A59%3A59&page=1&limit=25&sortBy=updatedAt&sortDir=DESC
Authorization: Bearer {access_token}
sortBySortiert nach
nameObjektname
createdAtErstellungszeitstempel
updatedAtZeitstempel der letzten Aktualisierung

Jeder sortBy-Wert lässt sich mit jedem sortDir-Wert kombinieren:

GET {api_url}/v1/twin/{contextId}/search?fieldFilters=%7B%22key%22%3A%22type%22%2C%22values%22%3A%5B%22poi%22%5D%7D&sortBy=name&sortDir=ASC
Authorization: Bearer {access_token}
GET {api_url}/v1/twin/{contextId}/search?fieldFilters=%7B%22key%22%3A%22type%22%2C%22values%22%3A%5B%22poi%22%5D%7D&sortBy=createdAt&sortDir=DESC
Authorization: Bearer {access_token}
GET {api_url}/v1/twin/{contextId}/search?fieldFilters=%7B%22key%22%3A%22type%22%2C%22values%22%3A%5B%22poi%22%5D%7D&sortBy=updatedAt&sortDir=DESC
Authorization: Bearer {access_token}

sortDir ist standardmäßig ASC, wenn nicht angegeben. Für sortBy gibt es kein dokumentiertes Standardfeld — wird er weggelassen, wird nach einem internen Relevanz-Score (absteigend) sortiert, mit id (aufsteigend) als Tiebreaker. Nur fieldFilters mit key: "name" beeinflusst diesen Score; jeder andere Filter ist ein reiner Ja/Nein-Abgleich ohne Einfluss auf das Ranking — wird sortBy also ohne einen name-Filter weggelassen, werden die Ergebnisse in der Praxis in id-Reihenfolge zurückgegeben. Dies ist ein Implementierungsdetail und keine garantierte Vertragsbedingung — setzen Sie sortBy daher immer explizit, wenn eine bestimmte Feldreihenfolge für Ihre Integration wichtig ist.

Innerhalb von metadataFilters- und additionalPropertyFilters-Werten kann ein Wert statt eines Literalabgleichs einen Vergleichsoperator oder einen Bereich tragen. Diese Syntax gilt nicht für fieldFilters — dort wird immer literal/als Enum abgeglichen (type, asset-type, name, id).

OperatorBeispielBedeutung
==123Gleich
!=!=123Ungleich
>>123Größer als
>=>=123Größer oder gleich
<<123Kleiner als
<=<=123Kleiner oder gleich
range:[a..b]range:[80..120]Beide Grenzen inklusive
range:(a..b)range:(80..120)Beide Grenzen exklusive
range:[a..b)range:[80..120)Untere Grenze inklusive, obere exklusive
range:(a..b]range:(80..120]Untere Grenze exklusive, obere inklusive

Ganzzahlen, Dezimalzahlen, negative Zahlen und wissenschaftliche Notation werden alle unterstützt, z. B. >=-40, =3.14 oder range:[1.5e+35..2.0e+35].

Es gibt zwei Wege, um nach Namen abzugleichen, und sie verhalten sich unterschiedlich:

ParameterAbgleichsstilKombinierbar mit anderen Filtern?
fieldFilters={"key":"name",...}Präfixabgleich, ohne UnschärfeJa — immer mit UND verknüpft
searchNameQuery + nameMatchcontains (Standard) oder exact, ohne UnschärfeJa — immer mit UND verknüpft

Verwenden Sie fieldFilters mit key: "name" für einen reinen Namens-Präfixabgleich, der sich unter denselben UND/ODER-Regeln kombiniert wie type oder asset-type. Verwenden Sie searchNameQuery mit nameMatch, wenn Sie eine präzise Teilstring- oder Exakt-Namenssuche ohne Unschärfe-Toleranz benötigen — zum Beispiel, um zu prüfen, ob ein Name wortgetreu existiert.

{
"results": [
{
"id": "5e1c0b3a-2d9a-4b7d-8f0b-9a2c8f1b7a10",
"name": "Fire extinguisher 12",
"type": "Poi",
"matchedFields": [
{ "matchKey": "name", "highlight": "Fire <em>extinguisher</em> 12" }
],
"createdAt": "2026-06-01T10:00:00.000Z",
"updatedAt": "2026-06-01T10:00:00.000Z",
"createdById": "8f0b9a2c-8f1b-4a10-9e1c-0b3a2d9a4b7d"
}
],
"count": 1
}

matchedFields zeigt, welches Feld oder welche Metadateneigenschaft getroffen wurde, wobei der getroffene Text in <em> eingeschlossen ist. matchKey ist entweder ein Feldname der obersten Ebene (z. B. name) oder @<metadata-path> für einen getroffenen verschachtelten Metadaten- oder Eigenschaftswert.

Ein einzelnes Ergebnis kann mehrere matchedFields-Einträge enthalten — einen pro Feld oder Metadateneigenschaft, die getroffen wurde. Zum Beispiel liefert eine kombinierte Anfrage aus einem fieldFilters-Namensabgleich und einer metadataFilters-Anfrage, die sowohl auf den Namen des Objekts als auch auf einen Inspektions-Metadatenwert trifft, Folgendes zurück:

{
"id": "5e1c0b3a-2d9a-4b7d-8f0b-9a2c8f1b7a10",
"name": "Pressure gauge 04",
"type": "Poi",
"matchedFields": [
{ "matchKey": "name", "highlight": "<em>Pressure</em> gauge 04" },
{ "matchKey": "@inspection.status", "highlight": "<em>Warning</em>: recalibration due" }
],
"createdAt": "2026-06-01T10:00:00.000Z",
"updatedAt": "2026-06-01T10:00:00.000Z",
"createdById": "8f0b9a2c-8f1b-4a10-9e1c-0b3a2d9a4b7d"
}

Hervorhebungs-Fragmente werden HTML-escaped, bevor die <em>-Marker eingefügt werden — jedes <, > oder & im getroffenen Text kommt also als &lt;, &gt; oder &amp; an statt als rohes Markup. Das ist sicher, um es direkt in HTML zu rendern, ohne einen zweiten Escaping-Durchlauf — dekodieren Sie es aber zuerst, wenn Sie den reinen Textwert benötigen.

SituationVerhalten
Keine Filter (oder alle leer)Gibt jedes Business-Objekt im Twin zurück, bis zu limit, ohne Ranking (match_all).
Ein nicht erkannter fieldFilters-SchlüsselWird stillschweigend ignoriert — der Filter trägt nichts zur Abfrage bei, löst keinen 400 aus.
Ein metadataFilters-/additionalPropertyFilters-Wert von * oder ""Wird übersprungen. Werden alle Werte im values-Array eines Filters auf diese Weise übersprungen, verlangt der Filter weiterhin, dass das Objekt eine Eigenschaft mit diesem Schlüssel besitzt — er wird zu einer reinen Prüfung auf das Vorhandensein des Schlüssels, ohne Wertebeschränkung.

Namenspräfix-Suche:

GET {api_url}/v1/twin/{contextId}/search?fieldFilters=%7B%22key%22%3A%22name%22%2C%22values%22%3A%5B%22extinguisher%22%5D%7D
Authorization: Bearer {access_token}

Namenssuche (enthält), sortiert nach Name:

GET {api_url}/v1/twin/{contextId}/search?searchNameQuery=Pump&nameMatch=contains&sortBy=name&sortDir=ASC
Authorization: Bearer {access_token}
StatusUrsache
400 Bad RequestEin Wert von fieldFilters, metadataFilters oder additionalPropertyFilters ist kein gültiges JSON oder entspricht nicht der Form { key, values }.

Wiederholte Filterparameter (mehrere fieldFilters, metadataFilters oder additionalPropertyFilters mit unterschiedlichen JSON-Werten) lassen sich nicht mit den dict-basierten params von requests abbilden — ein Dict kann pro Schlüssel nur einen Wert halten. Erstellen Sie den Query-String stattdessen selbst mit urllib.parse.urlencode und einer Liste von Tupeln:

import json
import requests
from urllib.parse import urlencode
API_URL = "https://<your-regional-api-url>"
TOKEN = "<access_token>"
CONTEXT_ID = "<twin-id>"
headers = {"Authorization": f"Bearer {TOKEN}"}
params = [
("fieldFilters", json.dumps({"key": "type", "values": ["poi"]})),
("metadataFilters", json.dumps({"key": "inspection.pressure", "values": ["range:[80..120]"]})),
("sortBy", "name"),
("sortDir", "ASC"),
]
response = requests.get(
f"{API_URL}/v1/twin/{CONTEXT_ID}/search?{urlencode(params)}",
headers=headers,
).json()
for result in response["results"]:
print(result["type"], result["name"], result["id"])

GET /v1/nodes/search durchsucht die Knotenhierarchie Ihrer Organisation — Divisions, Sites, Ordner, Twins, Asset-Bibliotheken und Dateien — statt der Business-Objekte innerhalb eines Twins. Die Organisation wird aus dem Access Token ermittelt und nicht als Parameter übergeben.

ParameterTypHinweise
nodeTypesArray von DataNodeTypeFiltert auf einen oder mehrere Knotentypen. Parameter wiederholen, z. B. ?nodeTypes=Site&nodeTypes=Folder. Werte: Organization, Site, Pointcloud, Mesh, SiteFile, Folder, Project, Division, Artifact, DataBundle, Twin, AssetLibrary.
excludeNodeTypesArray von DataNodeTypeSchließt einen oder mehrere Knotentypen aus. Gleiche Wiederholungssyntax.
searchNameQueryStringFilter nach Knotenname.
nameMatchexact | containsAbgleichsmodus für searchNameQuery. Standard contains.
parentIdUUIDNur direkte Kinder dieses Knotens.
ancestorIdUUIDNachfahren auf jeder Ebene, ohne den Vorfahren selbst. Für verschachtelte Inhalte unter einer Site oder einem Ordner; für direkte Kinder parentId verwenden.
createdByIdUUIDFilter nach Ersteller.
createdBefore / createdAfterZeitstempelStreng davor/danach. Format YYYY-MM-DDTHH:mm:ss.
updatedBefore / updatedAfterZeitstempelGleiches Format.
bytesStoredGanzzahlExakter Abgleich.
minBytesStored / maxBytesStoredGanzzahlInklusive Grenzen.
childrenCountGanzzahlExakter Abgleich.
minChildrenCount / maxChildrenCountGanzzahlInklusive Grenzen.
includesThumbnail'true' | 'false'Signierte Thumbnail-URLs einschließen, sofern verfügbar. Standard 'false'.
pageGanzzahlStandard 1.
limitGanzzahl150, Standard 20.
sortByname | createdAt | updatedAt | bytesStored | childrenCountSortierfeld.
sortDirASC | DESCSortierrichtung. Standard ASC.
{
"items": [
{
"id": "a6f75b3c-f261-4b27-9a2a-9a6cc1234c53",
"createdAt": "2026-06-01T10:00:00.000Z",
"updatedAt": "2026-06-01T10:00:00.000Z",
"name": "Building A",
"type": "Site",
"createdById": "8f0b9a2c-8f1b-4a10-9e1c-0b3a2d9a4b7d",
"parentId": "d2a1c4b7-3e10-4f2c-9a6b-7c1d8e2f3a45",
"childrenCount": 4,
"bytesStored": 15728640,
"thumbnailSignedUrl": null
}
],
"total": 1
}

Alle Sites unter einem Vorfahrenknoten:

GET {api_url}/v1/nodes/search?nodeTypes=Site&ancestorId=d2a1c4b7-3e10-4f2c-9a6b-7c1d8e2f3a45
Authorization: Bearer {access_token}

Ordner, deren Name mit “Archive” beginnt, sortiert nach Name:

GET {api_url}/v1/nodes/search?nodeTypes=Folder&searchNameQuery=Archive&nameMatch=contains&sortBy=name&sortDir=ASC
Authorization: Bearer {access_token}
import requests
from urllib.parse import urlencode
API_URL = "https://<your-regional-api-url>"
TOKEN = "<access_token>"
ANCESTOR_ID = "<division-or-site-id>"
headers = {"Authorization": f"Bearer {TOKEN}"}
params = [
("nodeTypes", "Site"),
("ancestorId", ANCESTOR_ID),
("sortBy", "name"),
("sortDir", "ASC"),
]
response = requests.get(
f"{API_URL}/v1/nodes/search?{urlencode(params)}",
headers=headers,
).json()
for node in response["items"]:
print(node["type"], node["name"], node["id"])

Um Ressourcen unter einem von der Knotensuche zurückgegebenen Knoten zu erstellen, siehe Einen Data Bundle erstellen.