Aller au contenu

Rechercher des objets métier et des nœuds

L’API RealityConnect propose deux routes de recherche à la portée différente : la recherche d’objets métier explore l’intérieur d’un twin pour les POI, zones, assets et leurs métadonnées, tandis que la recherche de nœuds explore la hiérarchie de nœuds de votre organisation (sites, dossiers, twins et fichiers). Les deux routes sont expérimentales et peuvent évoluer.


MéthodeCheminScopeObjectif
GET/v1/twin/{contextId}/searchBasicRechercher des objets métier et des métadonnées dans un twin
GET/v1/nodes/searchReadHierarchyRechercher dans la hiérarchie de nœuds de l’organisation

GET /v1/twin/{contextId}/search recherche les POI, zones, box assets, mesures et autres objets métier dans un twin donné (ou l’un de ses sites/brouillons, identifié par contextId), en comparant le nom, les champs réservés, les métadonnées d’asset et les propriétés spécifiques à l’objet.

ParamètreTypeRemarques
fieldFilterstableau d’objets JSONFiltres à clés réservées. Voir ci-dessous.
metadataFilterstableau d’objets JSONCompare les propriétés de métadonnées d’asset du twin. Voir ci-dessous.
additionalPropertyFilterstableau d’objets JSONCompare les propriétés spécifiques au type d’objet (p. ex. l’icon d’un POI). Voir ci-dessous.
pageentierPositif, valeur par défaut 1.
limitentier150, valeur par défaut 50.
searchNameQuerychaîneFiltre de nom dédié, indépendant du nom dans fieldFilters.
nameMatchexact | containsMode de comparaison pour searchNameQuery. Par défaut contains.
createdByIduuidFiltre par créateur.
createdBefore / createdAfterhorodatageStrictement avant/après. Format YYYY-MM-DDTHH:mm:ss (sans décalage de fuseau horaire, sans millisecondes).
updatedBefore / updatedAfterhorodatageMême format.
sortByname | createdAt | updatedAtChamp de tri.
sortDirASC | DESCSens du tri.

fieldFilters, metadataFilters et additionalPropertyFilters sont chacun envoyés sous forme d’une chaîne d’objet JSON par filtre, le paramètre étant répété pour plusieurs filtres :

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

Chaque objet de filtre a la forme { "key": string, "values": string[] }. Plusieurs valeurs dans le tableau values d’un filtre sont combinées avec OR.

fieldFilters n’accepte que ces clés réservées — toute autre clé est silencieusement ignorée :

CléCorrespond à
typeType d’objet métier. Accepte soit la valeur d’énumération (Poi, Zone, BoxAsset, CubePrimitive, PlanePrimitive, DistanceMeasure, CoordinateMeasure, DiameterMeasure, SurfaceMeasure, OrthogonalMeasure, Cut, ModelAsset), soit son jeton kebab-case normalisé — une version en minuscules avec traits d’union du nom PascalCase, p. ex. BoxAssetbox-asset.
asset-typeLe type d’asset de l’objet (correspond à assetTypeId). Correspondance exacte.
nameCorrespondance par préfixe sur le nom uniquement, sans tolérance aux fautes.
idCorrespondance exacte de l’identifiant de l’objet.

Les valeurs de fieldFilters sont toujours de simples chaînes ou jetons d’énumération — la syntaxe numérique/de plage ci-dessous ne s’y applique pas.

metadataFilters et additionalPropertyFilters ciblent par clé une propriété de métadonnées définie par le schéma (metadataFilters) ou une propriété spécifique au type d’objet qui ne fait pas partie des métadonnées communes (additionalPropertyFilters, p. ex. l’icon d’un POI). Chaque valeur de values prend en charge :

Syntaxe de valeurSignification
Chaîne simpleCorrespondance exacte. Plusieurs chaînes simples dans values sont combinées avec OR.
* ou chaîne videIgnorée — si c’est la seule valeur, le filtre ne teste que la présence de la clé.
=123, !=123, >123, >=123, <123, <=123Comparaison numérique. Entiers, décimaux et notation scientifique (p. ex. 1.5e+35) pris en charge.
range:[1..10]Plage numérique inclusive.
range:(1..10)Plage numérique exclusive.
range:[1..10) / range:(1..10]Bornes mixtes inclusive/exclusive.
true / falseadditionalPropertyFilters uniquement — compare littéralement une propriété booléenne.

fieldFilters, metadataFilters et additionalPropertyFilters se combinent selon une logique ET : un résultat doit satisfaire chaque filtre. Au sein d’un même filtre, les valeurs de son tableau values sont combinées avec OU — ainsi, deux objets fieldFilters partageant la même key se comportent comme « l’une ou l’autre valeur correspond », tandis que les filtres sur des clés différentes (ou des tableaux de filtres différents) restreignent tous davantage l’ensemble de résultats.

Filtre de type combiné à une plage numérique de métadonnées (POI dont la pression d’inspection enregistrée est comprise entre 80 et 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}

Type d’asset combiné à un filtre de nom, mises à jour les plus récentes en premier :

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}

Cela signifie : les objets dont le type d’asset est pump et dont le nom commence par « vibration », triés par date de mise à jour la plus récente.

Deux fieldFilters sur la même clé (combinés avec OU) associés à un fieldFilters sur une clé différente (combiné avec ET) — POI ou zones, restreints au type d’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 littéral booléen additionalPropertyFilters combiné à une correspondance de chaîne metadataFilters — POI actifs dont les métadonnées liées à l’icône enregistrent un statut « 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}

Une requête complète combinant les trois entrées de filtrage, un filtre de nom dédié, une plage de dates, la pagination et le tri — illustrant la forme complète de la requête :

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}
sortByTrie par
nameNom de l’objet
createdAtHorodatage de création
updatedAtHorodatage de dernière mise à jour

Chaque valeur de sortBy se combine avec l’une ou l’autre valeur de 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 vaut ASC par défaut lorsqu’il est omis. sortBy n’a pas de champ par défaut documenté — si vous l’omettez, le tri se fait par score de pertinence interne (ordre décroissant), avec id (ordre croissant) comme critère de départage. Seul fieldFilters avec key: "name" influe sur ce score ; tout autre filtre est une correspondance binaire pure, sans effet sur le classement, donc en pratique, omettre sortBy sans filtre name renvoie les résultats triés par id. Il s’agit d’un détail d’implémentation, et non d’un contrat garanti — définissez sortBy explicitement chaque fois qu’un ordre de champ précis importe pour votre intégration.

Dans les valeurs de metadataFilters et additionalPropertyFilters, une valeur peut porter un opérateur de comparaison ou une plage au lieu d’une correspondance littérale. Cette syntaxe ne s’applique pas à fieldFilters — ces derniers utilisent toujours une correspondance littérale/d’énumération (type, asset-type, name, id).

OpérateurExempleSignification
==123Égal à
!=!=123Différent de
>>123Supérieur à
>=>=123Supérieur ou égal à
<<123Inférieur à
<=<=123Inférieur ou égal à
range:[a..b]range:[80..120]Inclusif sur les deux bornes
range:(a..b)range:(80..120)Exclusif sur les deux bornes
range:[a..b)range:[80..120)Borne inférieure inclusive, borne supérieure exclusive
range:(a..b]range:(80..120]Borne inférieure exclusive, borne supérieure inclusive

Les entiers, les décimaux, les nombres négatifs et la notation scientifique sont tous pris en charge, p. ex. >=-40, =3.14, ou range:[1.5e+35..2.0e+35].

Il existe deux façons de faire correspondre un nom, et elles se comportent différemment :

ParamètreStyle de correspondanceSe combine avec d’autres filtres ?
fieldFilters={"key":"name",...}Correspondance par préfixe, sans tolérance aux fautesOui — toujours combiné avec ET
searchNameQuery + nameMatchcontains (par défaut) ou exact, sans tolérance aux fautesOui — toujours combiné avec ET

Utilisez fieldFilters avec key: "name" pour une correspondance par préfixe portant uniquement sur le nom, qui suit les mêmes règles ET/OU que type ou asset-type. Utilisez searchNameQuery avec nameMatch lorsque vous avez besoin d’une recherche précise par sous-chaîne ou par nom exact, sans aucune tolérance aux fautes — par exemple pour vérifier qu’un nom existe tel quel.

{
"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 indique quel champ ou quelle propriété de métadonnées a correspondu, le texte correspondant étant entouré de <em>. matchKey est soit un nom de champ racine (p. ex. name), soit @<metadata-path> pour une valeur imbriquée de métadonnées ou de propriété correspondante.

Un même résultat peut porter plusieurs entrées matchedFields — une par champ ou propriété de métadonnées ayant correspondu. Par exemple, une requête combinant une correspondance de nom fieldFilters et un metadataFilters qui correspond à la fois au nom de l’objet et à une valeur de métadonnées d’inspection renvoie :

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

Les fragments surlignés sont échappés en HTML avant l’insertion des balises <em> : tout <, > ou & présent dans le texte correspondant arrive sous la forme &lt;, &gt; ou &amp; plutôt que comme balisage brut — ce qui permet de les afficher directement en HTML sans second passage d’échappement, mais pensez à les décoder d’abord si vous avez besoin de la valeur en texte brut.

SituationComportement
Aucun filtre (ou tous vides)Renvoie tous les objets métier du twin, jusqu’à limit, sans classement (match_all).
Une clé fieldFilters non reconnueSilencieusement ignorée — le filtre ne contribue en rien à la requête, il ne déclenche pas d’erreur 400.
Une valeur metadataFilters/additionalPropertyFilters égale à * ou ""Ignorée. Si toutes les valeurs du tableau values de ce filtre sont ainsi ignorées, le filtre exige tout de même que l’objet possède une propriété à cette clé — il devient une simple vérification de présence de clé, sans contrainte sur la valeur.

Recherche par préfixe de nom :

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}

Recherche par sous-chaîne de nom, triée par nom :

GET {api_url}/v1/twin/{contextId}/search?searchNameQuery=Pump&nameMatch=contains&sortBy=name&sortDir=ASC
Authorization: Bearer {access_token}
StatutCause
400 Bad RequestUne valeur de fieldFilters, metadataFilters ou additionalPropertyFilters n’est pas un JSON valide, ou ne correspond pas à la forme { key, values }.

Les paramètres de filtre répétés (plusieurs fieldFilters, metadataFilters ou additionalPropertyFilters avec des valeurs JSON différentes) ne peuvent pas être construits avec les params basés sur un dict de requests — un dict ne peut contenir qu’une seule valeur par clé. Construisez plutôt vous-même la chaîne de requête avec urllib.parse.urlencode et une liste de tuples :

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 recherche dans la hiérarchie de nœuds de votre organisation — divisions, sites, dossiers, twins, bibliothèques d’assets et fichiers de données — plutôt que dans les objets métier d’un twin. L’organisation est déterminée à partir du jeton d’accès, et non transmise en paramètre.

ParamètreTypeRemarques
nodeTypestableau de DataNodeTypeFiltre sur un ou plusieurs types de nœuds. Répétez le paramètre, p. ex. ?nodeTypes=Site&nodeTypes=Folder. Valeurs : Organization, Site, Pointcloud, Mesh, SiteFile, Folder, Project, Division, Artifact, DataBundle, Twin, AssetLibrary.
excludeNodeTypestableau de DataNodeTypeExclut un ou plusieurs types de nœuds. Même syntaxe de répétition.
searchNameQuerychaîneFiltre par nom de nœud.
nameMatchexact | containsMode de comparaison pour searchNameQuery. Par défaut contains.
parentIduuidUniquement les enfants directs de ce nœud.
ancestorIduuidDescendants à toute profondeur, à l’exclusion de l’ancêtre lui-même. À utiliser pour le contenu imbriqué sous un site ou un dossier ; utilisez parentId pour les enfants directs uniquement.
createdByIduuidFiltre par créateur.
createdBefore / createdAfterhorodatageStrictement avant/après. Format YYYY-MM-DDTHH:mm:ss.
updatedBefore / updatedAfterhorodatageMême format.
bytesStoredentierCorrespondance exacte.
minBytesStored / maxBytesStoredentierBornes inclusives.
childrenCountentierCorrespondance exacte.
minChildrenCount / maxChildrenCountentierBornes inclusives.
includesThumbnail'true' | 'false'Inclut les URL de miniature signées lorsqu’elles sont disponibles. Par défaut 'false'.
pageentierPar défaut 1.
limitentier150, valeur par défaut 20.
sortByname | createdAt | updatedAt | bytesStored | childrenCountChamp de tri.
sortDirASC | DESCSens du tri. Par défaut 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
}

Tous les sites sous un nœud ancêtre :

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

Dossiers dont le nom commence par « Archive », triés par nom :

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"])

Pour créer des ressources sous un nœud renvoyé par la recherche de nœuds, consultez Créer un data bundle.