Ricerca di oggetti business e nodi
L’API RealityConnect espone due route di ricerca con ambiti diversi: la ricerca di oggetti business cerca all’interno di un twin POI, zone, asset e i relativi metadati, mentre la ricerca dei nodi cerca nella gerarchia dei nodi della tua organizzazione (siti, cartelle, twin e file). Entrambe le route sono sperimentali e possono cambiare.
Endpoint
Sezione intitolata “Endpoint”| Metodo | Percorso | Ambito | Scopo |
|---|---|---|---|
GET | /v1/twin/{contextId}/search | Basic | Cerca oggetti business e metadati all’interno di un twin |
GET | /v1/nodes/search | ReadHierarchy | Cerca nella gerarchia dei nodi dell’organizzazione |
Ricerca di oggetti business
Sezione intitolata “Ricerca di oggetti business”GET /v1/twin/{contextId}/search cerca POI, zone, box asset, misurazioni e altri oggetti business all’interno di un singolo twin (o di uno dei suoi siti/bozze, identificato da contextId), confrontando nome, campi riservati, metadati dell’asset e proprietà specifiche dell’oggetto.
Parametri della query
Sezione intitolata “Parametri della query”| Parametro | Tipo | Note |
|---|---|---|
fieldFilters | array di oggetti JSON | Filtri su chiavi riservate. Vedi sotto. |
metadataFilters | array di oggetti JSON | Confronta le proprietà di metadati asset del twin. Vedi sotto. |
additionalPropertyFilters | array di oggetti JSON | Confronta proprietà specifiche del tipo di oggetto (es. l’icon di un POI). Vedi sotto. |
page | intero | Positivo, predefinito 1. |
limit | intero | 1–50, predefinito 50. |
searchNameQuery | string | Filtro nome dedicato, indipendente dal nome in fieldFilters. |
nameMatch | exact | contains | Modalità di corrispondenza per searchNameQuery. Predefinito contains. |
createdById | uuid | Filtra per creatore. |
createdBefore / createdAfter | timestamp | Rigorosamente prima/dopo. Formato YYYY-MM-DDTHH:mm:ss (senza offset del fuso orario, senza millisecondi). |
updatedBefore / updatedAfter | timestamp | Stesso formato. |
sortBy | name | createdAt | updatedAt | Campo di ordinamento. |
sortDir | ASC | DESC | Direzione di ordinamento. |
fieldFilters, metadataFilters e additionalPropertyFilters vengono inviati ciascuno come una stringa oggetto JSON per filtro, ripetendo il parametro di query per più filtri:
?fieldFilters={"key":"type","values":["poi"]}&fieldFilters={"key":"type","values":["zone"]}Ogni oggetto filtro ha la forma { "key": string, "values": string[] }. Più valori nell’array values di un filtro sono combinati con OR.
fieldFilters accetta solo queste chiavi riservate — qualsiasi altra chiave viene ignorata silenziosamente:
| Chiave | Confronta |
|---|---|
type | Tipo di oggetto business. Accetta il valore dell’enum (Poi, Zone, BoxAsset, CubePrimitive, PlanePrimitive, DistanceMeasure, CoordinateMeasure, DiameterMeasure, SurfaceMeasure, OrthogonalMeasure, Cut, ModelAsset) oppure il suo token normalizzato in kebab-case — una versione con trattini e minuscola del nome PascalCase, es. BoxAsset → box-asset. |
asset-type | Il tipo di asset dell’oggetto (mappato su assetTypeId). Corrispondenza esatta. |
name | Corrispondenza per prefisso sul nome, senza tolleranza fuzzy. |
id | Corrispondenza esatta dell’id dell’oggetto. |
I valori di fieldFilters sono sempre stringhe semplici o token dell’enum — la sintassi numerica/di intervallo sotto non si applica a essi.
metadataFilters e additionalPropertyFilters individuano tramite chiave una proprietà di metadati definita dallo schema (metadataFilters) o una proprietà specifica del tipo di oggetto non compresa nei metadati comuni (additionalPropertyFilters, es. l’icon di un POI). Ogni valore in values supporta:
| Sintassi del valore | Significato |
|---|---|
| Stringa semplice | Corrispondenza esatta. Più stringhe semplici in values sono combinate con OR. |
* o stringa vuota | Ignorato — se è l’unico valore, il filtro corrisponde solo in base alla presenza della chiave. |
=123, !=123, >123, >=123, <123, <=123 | Confronto numerico. Sono supportati interi, decimali e notazione scientifica (es. 1.5e+35). |
range:[1..10] | Intervallo numerico inclusivo. |
range:(1..10) | Intervallo numerico esclusivo. |
range:[1..10) / range:(1..10] | Limiti misti inclusivo/esclusivo. |
true / false | Solo additionalPropertyFilters — confronta letteralmente una proprietà booleana. |
Combinazione dei filtri
Sezione intitolata “Combinazione dei filtri”fieldFilters, metadataFilters e additionalPropertyFilters si combinano con semantica AND: un risultato deve soddisfare ogni filtro. All’interno di un singolo filtro, i valori nel suo array values sono combinati con OR — quindi due oggetti fieldFilters che condividono la stessa key si comportano come “corrisponde l’uno o l’altro valore”, mentre i filtri su chiavi diverse (o su array di filtri diversi) restringono ulteriormente l’insieme dei risultati.
Filtro per tipo combinato con un intervallo numerico sui metadati (POI con una pressione di ispezione registrata tra 80 e 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%7DAuthorization: Bearer {access_token}Tipo di asset combinato con un filtro nome, aggiornamenti più recenti per primi:
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=DESCAuthorization: Bearer {access_token}Questo significa: oggetti il cui tipo di asset è pump e il cui nome inizia con “vibration”, ordinati per data di aggiornamento più recente.
Due fieldFilters sulla stessa chiave (combinati con OR) uniti a un fieldFilters su una chiave diversa (combinato con AND) — POI o zone, ristretti al tipo di asset 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%7DAuthorization: Bearer {access_token}Un letterale booleano additionalPropertyFilters combinato con una corrispondenza stringa metadataFilters — POI attivi i cui metadati adiacenti all’icona registrano uno stato di “warning”:
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%7DAuthorization: Bearer {access_token}Una richiesta completa che combina tutti e tre gli input di filtro, un filtro nome dedicato, un intervallo di date, la paginazione e l’ordinamento — mostrando la forma completa della richiesta:
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=DESCAuthorization: Bearer {access_token}Ordinamento
Sezione intitolata “Ordinamento”sortBy | Ordina per |
|---|---|
name | Nome dell’oggetto |
createdAt | Timestamp di creazione |
updatedAt | Timestamp dell’ultimo aggiornamento |
Ogni valore di sortBy si combina con entrambi i valori di sortDir:
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=ASCAuthorization: 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=DESCAuthorization: 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=DESCAuthorization: Bearer {access_token}sortDir è predefinito su ASC quando omesso. sortBy non ha un campo predefinito documentato — se lo ometti, l’ordinamento avviene per punteggio di rilevanza interno (decrescente), con id (crescente) come criterio di spareggio. Solo fieldFilters con key: "name" influisce su questo punteggio; ogni altro filtro è una semplice corrispondenza sì/no senza effetto sulla classificazione, quindi in pratica, omettere sortBy senza un filtro name restituisce i risultati in ordine di id. Questo è un dettaglio implementativo, non un contratto garantito — imposta sortBy esplicitamente ogni volta che un ordine specifico dei campi è importante per la tua integrazione.
Filtri numerici e di intervallo
Sezione intitolata “Filtri numerici e di intervallo”All’interno dei valori di metadataFilters e additionalPropertyFilters, un valore può portare un operatore di confronto o un intervallo invece di una corrispondenza letterale. Questa sintassi non si applica a fieldFilters — quelli sono sempre corrispondenze letterali/enum (type, asset-type, name, id).
| Operatore | Esempio | Significato |
|---|---|---|
= | =123 | Uguale a |
!= | !=123 | Diverso da |
> | >123 | Maggiore di |
>= | >=123 | Maggiore o uguale a |
< | <123 | Minore di |
<= | <=123 | Minore o uguale a |
range:[a..b] | range:[80..120] | Inclusivo su entrambi i limiti |
range:(a..b) | range:(80..120) | Esclusivo su entrambi i limiti |
range:[a..b) | range:[80..120) | Limite inferiore inclusivo, superiore esclusivo |
range:(a..b] | range:(80..120] | Limite inferiore esclusivo, superiore inclusivo |
Interi, decimali, numeri negativi e notazione scientifica sono tutti supportati, es. >=-40, =3.14, oppure range:[1.5e+35..2.0e+35].
Filtro nome vs. query nome
Sezione intitolata “Filtro nome vs. query nome”Esistono due modi per confrontare per nome, e si comportano in modo diverso:
| Parametro | Stile di corrispondenza | Si combina con altri filtri? |
|---|---|---|
fieldFilters={"key":"name",...} | Corrispondenza per prefisso, senza tolleranza fuzzy | Sì — sempre in AND |
searchNameQuery + nameMatch | contains (predefinito) o exact, nessuna tolleranza fuzzy | Sì — sempre in AND |
Usa fieldFilters con key: "name" per una corrispondenza per prefisso solo sul nome che si combina secondo le stesse regole AND/OR di type o asset-type. Usa searchNameQuery con nameMatch quando hai bisogno di una ricerca precisa per sottostringa o per nome esatto senza tolleranza fuzzy — ad esempio, per verificare che un nome esista letteralmente.
Risposta
Sezione intitolata “Risposta”{ "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 mostra quale campo o proprietà di metadati ha trovato corrispondenza, con il testo corrispondente racchiuso in <em>. matchKey è un nome di campo radice (es. name) oppure @<metadata-path> per un valore di metadati o proprietà annidata che ha trovato corrispondenza.
Dettagli sull’evidenziazione
Sezione intitolata “Dettagli sull’evidenziazione”Un singolo risultato può contenere più voci matchedFields — una per ogni campo o proprietà di metadati che ha trovato corrispondenza. Ad esempio, una richiesta combinata di corrispondenza nome tramite fieldFilters e una richiesta metadataFilters che corrisponde sia al nome dell’oggetto sia a un valore di metadati di ispezione restituisce:
{ "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"}I frammenti evidenziati vengono sottoposti a escape HTML prima che vengano inseriti i marcatori <em>, quindi qualsiasi <, > o & nel testo corrispondente arriva come <, > o & anziché come markup grezzo — sicuro da visualizzare direttamente in HTML senza un secondo passaggio di escape, ma decodificalo prima se hai bisogno del valore in testo semplice.
Casi limite
Sezione intitolata “Casi limite”| Situazione | Comportamento |
|---|---|
| Nessun filtro (o tutti vuoti) | Restituisce ogni oggetto business nel twin, fino a limit, senza classificazione (match_all). |
Una chiave fieldFilters non riconosciuta | Ignorata silenziosamente — il filtro non contribuisce in alcun modo alla query, non genera un 400. |
Un valore metadataFilters/additionalPropertyFilters pari a * o "" | Ignorato. Se ogni valore nell’array values di quel filtro viene ignorato in questo modo, il filtro richiede comunque che l’oggetto abbia una proprietà a quella chiave — diventa un controllo di presenza della chiave senza vincoli sul valore. |
Ricerca per prefisso del nome:
GET {api_url}/v1/twin/{contextId}/search?fieldFilters=%7B%22key%22%3A%22name%22%2C%22values%22%3A%5B%22extinguisher%22%5D%7DAuthorization: Bearer {access_token}Ricerca per contenuto del nome ordinata per nome:
GET {api_url}/v1/twin/{contextId}/search?searchNameQuery=Pump&nameMatch=contains&sortBy=name&sortDir=ASCAuthorization: Bearer {access_token}Casi di errore
Sezione intitolata “Casi di errore”| Stato | Causa |
|---|---|
400 Bad Request | Un valore di fieldFilters, metadataFilters o additionalPropertyFilters non è JSON valido, oppure non corrisponde alla forma { key, values }. |
Esempio completo
Sezione intitolata “Esempio completo”I parametri di filtro ripetuti (più fieldFilters, metadataFilters o additionalPropertyFilters con valori JSON diversi) non possono essere costruiti con il params basato su dizionario di requests — un dizionario ammette un solo valore per chiave. Costruisci tu stesso la query string con urllib.parse.urlencode e una lista di tuple:
import jsonimport requestsfrom 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"])Ricerca dei nodi
Sezione intitolata “Ricerca dei nodi”GET /v1/nodes/search cerca nella gerarchia dei nodi della tua organizzazione — divisioni, siti, cartelle, twin, librerie di asset e file di dati — anziché negli oggetti business all’interno di un twin. L’organizzazione viene risolta dal token di accesso, non passata come parametro.
Parametri della query
Sezione intitolata “Parametri della query”| Parametro | Tipo | Note |
|---|---|---|
nodeTypes | array di DataNodeType | Filtra per uno o più tipi di nodo. Ripeti il parametro, es. ?nodeTypes=Site&nodeTypes=Folder. Valori: Organization, Site, Pointcloud, Mesh, SiteFile, Folder, Project, Division, Artifact, DataBundle, Twin, AssetLibrary. |
excludeNodeTypes | array di DataNodeType | Esclude uno o più tipi di nodo. Stessa sintassi ripetuta. |
searchNameQuery | string | Filtra per nome del nodo. |
nameMatch | exact | contains | Modalità di corrispondenza per searchNameQuery. Predefinito contains. |
parentId | uuid | Solo i figli diretti di questo nodo. |
ancestorId | uuid | Discendenti a qualsiasi profondità, escluso l’antenato stesso. Usalo per contenuti annidati sotto un sito o una cartella; usa parentId solo per i figli diretti. |
createdById | uuid | Filtra per creatore. |
createdBefore / createdAfter | timestamp | Rigorosamente prima/dopo. Formato YYYY-MM-DDTHH:mm:ss. |
updatedBefore / updatedAfter | timestamp | Stesso formato. |
bytesStored | intero | Corrispondenza esatta. |
minBytesStored / maxBytesStored | intero | Limiti inclusivi. |
childrenCount | intero | Corrispondenza esatta. |
minChildrenCount / maxChildrenCount | intero | Limiti inclusivi. |
includesThumbnail | 'true' | 'false' | Include URL di miniature firmate quando disponibili. Predefinito 'false'. |
page | intero | Predefinito 1. |
limit | intero | 1–50, predefinito 20. |
sortBy | name | createdAt | updatedAt | bytesStored | childrenCount | Campo di ordinamento. |
sortDir | ASC | DESC | Direzione di ordinamento. Predefinito ASC. |
Risposta
Sezione intitolata “Risposta”{ "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}Tutti i siti sotto un nodo antenato:
GET {api_url}/v1/nodes/search?nodeTypes=Site&ancestorId=d2a1c4b7-3e10-4f2c-9a6b-7c1d8e2f3a45Authorization: Bearer {access_token}Cartelle il cui nome inizia con “Archive”, ordinate per nome:
GET {api_url}/v1/nodes/search?nodeTypes=Folder&searchNameQuery=Archive&nameMatch=contains&sortBy=name&sortDir=ASCAuthorization: Bearer {access_token}import requestsfrom 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"])Passo successivo
Sezione intitolata “Passo successivo”Per creare risorse sotto un nodo restituito dalla ricerca dei nodi, consulta Creazione di un data bundle.