Salta ai contenuti

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.


MetodoPercorsoAmbitoScopo
GET/v1/twin/{contextId}/searchBasicCerca oggetti business e metadati all’interno di un twin
GET/v1/nodes/searchReadHierarchyCerca nella gerarchia dei nodi dell’organizzazione

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.

ParametroTipoNote
fieldFiltersarray di oggetti JSONFiltri su chiavi riservate. Vedi sotto.
metadataFiltersarray di oggetti JSONConfronta le proprietà di metadati asset del twin. Vedi sotto.
additionalPropertyFiltersarray di oggetti JSONConfronta proprietà specifiche del tipo di oggetto (es. l’icon di un POI). Vedi sotto.
pageinteroPositivo, predefinito 1.
limitintero150, predefinito 50.
searchNameQuerystringFiltro nome dedicato, indipendente dal nome in fieldFilters.
nameMatchexact | containsModalità di corrispondenza per searchNameQuery. Predefinito contains.
createdByIduuidFiltra per creatore.
createdBefore / createdAftertimestampRigorosamente prima/dopo. Formato YYYY-MM-DDTHH:mm:ss (senza offset del fuso orario, senza millisecondi).
updatedBefore / updatedAftertimestampStesso formato.
sortByname | createdAt | updatedAtCampo di ordinamento.
sortDirASC | DESCDirezione 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:

ChiaveConfronta
typeTipo 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. BoxAssetbox-asset.
asset-typeIl tipo di asset dell’oggetto (mappato su assetTypeId). Corrispondenza esatta.
nameCorrispondenza per prefisso sul nome, senza tolleranza fuzzy.
idCorrispondenza 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 valoreSignificato
Stringa sempliceCorrispondenza esatta. Più stringhe semplici in values sono combinate con OR.
* o stringa vuotaIgnorato — se è l’unico valore, il filtro corrisponde solo in base alla presenza della chiave.
=123, !=123, >123, >=123, <123, <=123Confronto 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 / falseSolo additionalPropertyFilters — confronta letteralmente una proprietà booleana.

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%7D
Authorization: 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=DESC
Authorization: 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%7D
Authorization: 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%7D
Authorization: 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=DESC
Authorization: Bearer {access_token}
sortByOrdina per
nameNome dell’oggetto
createdAtTimestamp di creazione
updatedAtTimestamp 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=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 è 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.

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).

OperatoreEsempioSignificato
==123Uguale a
!=!=123Diverso da
>>123Maggiore di
>=>=123Maggiore o uguale a
<<123Minore di
<=<=123Minore 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].

Esistono due modi per confrontare per nome, e si comportano in modo diverso:

ParametroStile di corrispondenzaSi combina con altri filtri?
fieldFilters={"key":"name",...}Corrispondenza per prefisso, senza tolleranza fuzzySì — sempre in AND
searchNameQuery + nameMatchcontains (predefinito) o exact, nessuna tolleranza fuzzySì — 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.

{
"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.

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 &lt;, &gt; o &amp; 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.

SituazioneComportamento
Nessun filtro (o tutti vuoti)Restituisce ogni oggetto business nel twin, fino a limit, senza classificazione (match_all).
Una chiave fieldFilters non riconosciutaIgnorata 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%7D
Authorization: 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=ASC
Authorization: Bearer {access_token}
StatoCausa
400 Bad RequestUn valore di fieldFilters, metadataFilters o additionalPropertyFilters non è JSON valido, oppure non corrisponde alla forma { key, values }.

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 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 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.

ParametroTipoNote
nodeTypesarray di DataNodeTypeFiltra 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.
excludeNodeTypesarray di DataNodeTypeEsclude uno o più tipi di nodo. Stessa sintassi ripetuta.
searchNameQuerystringFiltra per nome del nodo.
nameMatchexact | containsModalità di corrispondenza per searchNameQuery. Predefinito contains.
parentIduuidSolo i figli diretti di questo nodo.
ancestorIduuidDiscendenti a qualsiasi profondità, escluso l’antenato stesso. Usalo per contenuti annidati sotto un sito o una cartella; usa parentId solo per i figli diretti.
createdByIduuidFiltra per creatore.
createdBefore / createdAftertimestampRigorosamente prima/dopo. Formato YYYY-MM-DDTHH:mm:ss.
updatedBefore / updatedAftertimestampStesso formato.
bytesStoredinteroCorrispondenza esatta.
minBytesStored / maxBytesStoredinteroLimiti inclusivi.
childrenCountinteroCorrispondenza esatta.
minChildrenCount / maxChildrenCountinteroLimiti inclusivi.
includesThumbnail'true' | 'false'Include URL di miniature firmate quando disponibili. Predefinito 'false'.
pageinteroPredefinito 1.
limitintero150, predefinito 20.
sortByname | createdAt | updatedAt | bytesStored | childrenCountCampo di ordinamento.
sortDirASC | DESCDirezione di ordinamento. Predefinito 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
}

Tutti i siti sotto un nodo antenato:

GET {api_url}/v1/nodes/search?nodeTypes=Site&ancestorId=d2a1c4b7-3e10-4f2c-9a6b-7c1d8e2f3a45
Authorization: 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=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"])

Per creare risorse sotto un nodo restituito dalla ricerca dei nodi, consulta Creazione di un data bundle.