Búsqueda de objetos de negocio y nodos
La API de RealityConnect expone dos rutas de búsqueda con alcances distintos: la búsqueda de objetos de negocio busca dentro de un twin POIs, zonas, activos y sus metadatos, mientras que la búsqueda de nodos busca en la jerarquía de nodos de tu organización (sitios, carpetas, twins y archivos). Ambas rutas son experimentales y pueden cambiar.
Endpoints
Sección titulada «Endpoints»| Método | Ruta | Alcance | Propósito |
|---|---|---|---|
GET | /v1/twin/{contextId}/search | Basic | Buscar objetos de negocio y metadatos dentro de un twin |
GET | /v1/nodes/search | ReadHierarchy | Buscar en la jerarquía de nodos de la organización |
Búsqueda de objetos de negocio
Sección titulada «Búsqueda de objetos de negocio»GET /v1/twin/{contextId}/search busca POIs, zonas, box assets, medidas y otros objetos de negocio dentro de un único twin (o uno de sus sitios/borradores, identificado por contextId), comparando el nombre, los campos reservados, los metadatos del activo y las propiedades específicas del objeto.
Parámetros de consulta
Sección titulada «Parámetros de consulta»| Parámetro | Tipo | Notas |
|---|---|---|
fieldFilters | array de objetos JSON | Filtros de claves reservadas. Ver más abajo. |
metadataFilters | array de objetos JSON | Compara propiedades de metadatos de activo del twin. Ver más abajo. |
additionalPropertyFilters | array de objetos JSON | Compara propiedades específicas del tipo de objeto (p. ej. el icon de un POI). Ver más abajo. |
page | entero | Positivo, por defecto 1. |
limit | entero | 1–50, por defecto 50. |
searchNameQuery | string | Filtro de nombre dedicado, independiente del nombre en fieldFilters. |
nameMatch | exact | contains | Modo de coincidencia para searchNameQuery. Por defecto contains. |
createdById | uuid | Filtrar por creador. |
createdBefore / createdAfter | timestamp | Estrictamente antes/después. Formato YYYY-MM-DDTHH:mm:ss (sin desfase horario, sin milisegundos). |
updatedBefore / updatedAfter | timestamp | Mismo formato. |
sortBy | name | createdAt | updatedAt | Campo de ordenación. |
sortDir | ASC | DESC | Dirección de ordenación. |
Filtros
Sección titulada «Filtros»fieldFilters, metadataFilters y additionalPropertyFilters se envían cada uno como una cadena de objeto JSON por filtro, repitiendo el parámetro de consulta para varios filtros:
?fieldFilters={"key":"type","values":["poi"]}&fieldFilters={"key":"type","values":["zone"]}Cada objeto de filtro tiene la forma { "key": string, "values": string[] }. Varios valores dentro del array values de un mismo filtro se combinan con OR.
fieldFilters solo acepta estas claves reservadas — cualquier otra clave se ignora silenciosamente:
| Clave | Compara |
|---|---|
type | Tipo de objeto de negocio. Acepta el valor del enum (Poi, Zone, BoxAsset, CubePrimitive, PlanePrimitive, DistanceMeasure, CoordinateMeasure, DiameterMeasure, SurfaceMeasure, OrthogonalMeasure, Cut, ModelAsset) o su token normalizado en kebab-case — una versión con guiones y en minúsculas del nombre PascalCase, p. ej. BoxAsset → box-asset. |
asset-type | El tipo de activo del objeto (se asigna a assetTypeId). Coincidencia exacta. |
name | Coincidencia por prefijo solo en el nombre, sin difusidad. |
id | Coincidencia exacta del id del objeto. |
Los valores de fieldFilters son siempre strings simples o tokens de enum — la sintaxis numérica/de rango descrita abajo no se aplica a ellos.
metadataFilters y additionalPropertyFilters referencian por clave una propiedad de metadatos definida en el esquema (metadataFilters) o una propiedad específica del tipo de objeto que no forma parte de los metadatos comunes (additionalPropertyFilters, p. ej. el icon de un POI). Cada valor en values admite:
| Sintaxis del valor | Significado |
|---|---|
| String simple | Coincidencia exacta. Varios strings simples en values se combinan con OR. |
* o string vacío | Se omite — si es el único valor, el filtro compara solo por la presencia de la clave. |
=123, !=123, >123, >=123, <123, <=123 | Comparación numérica. Se admiten enteros, decimales y notación científica (p. ej. 1.5e+35). |
range:[1..10] | Rango numérico inclusivo. |
range:(1..10) | Rango numérico exclusivo. |
range:[1..10) / range:(1..10] | Límites mixtos inclusivo/exclusivo. |
true / false | Solo en additionalPropertyFilters — compara literalmente una propiedad booleana. |
Combinación de filtros
Sección titulada «Combinación de filtros»fieldFilters, metadataFilters y additionalPropertyFilters se combinan con semántica AND: un resultado debe satisfacer todos los filtros. Dentro de un mismo filtro, los valores de su array values se combinan con OR — de modo que dos objetos fieldFilters que comparten la misma key se comportan como “cualquiera de los valores coincide,” mientras que los filtros sobre claves distintas (o sobre arrays de filtro distintos) siguen reduciendo el conjunto de resultados.
Filtro de tipo combinado con un rango numérico de metadatos (POIs con una presión de inspección registrada entre 80 y 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 de activo combinado con un filtro de nombre, con las actualizaciones más recientes primero:
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}Esto significa: los objetos cuyo tipo de activo es pump y cuyo nombre empieza por “vibration”, ordenados por actualización más reciente.
Dos fieldFilters sobre la misma clave (combinados con OR) junto con un fieldFilters sobre una clave distinta (combinado con AND) — POIs o zonas, restringidos al tipo de activo 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 literal booleano de additionalPropertyFilters combinado con una coincidencia de string en metadataFilters — POIs activos cuyos metadatos relacionados con el icono registran un estado de “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 solicitud completa que combina las tres entradas de filtro, un filtro de nombre dedicado, un rango de fechas, paginación y ordenación — mostrando la forma completa de la solicitud:
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}Ordenación
Sección titulada «Ordenación»sortBy | Ordena por |
|---|---|
name | Nombre del objeto |
createdAt | Marca de tiempo de creación |
updatedAt | Marca de tiempo de última actualización |
Cada valor de sortBy se combina con cualquiera de los valores 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=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 toma por defecto ASC cuando se omite. sortBy no tiene un campo por defecto documentado — si se omite, ordena por una puntuación de relevancia interna (descendente), con id (ascendente) como criterio de desempate. Solo fieldFilters con key: "name" afecta a esa puntuación; el resto de filtros son una simple coincidencia sí/no sin efecto en la clasificación, así que en la práctica, omitir sortBy sin un filtro de name devuelve los resultados ordenados por id. Esto es un detalle de implementación, no un contrato garantizado — indica sortBy de forma explícita siempre que tu integración necesite un orden de campo concreto.
Filtros numéricos y de rango
Sección titulada «Filtros numéricos y de rango»Dentro de los valores de metadataFilters y additionalPropertyFilters, un valor puede llevar un operador de comparación o un rango en lugar de una coincidencia literal. Esta sintaxis no aplica a fieldFilters — esos siempre son coincidencias literales/de enum (type, asset-type, name, id).
| Operador | Ejemplo | Significado |
|---|---|---|
= | =123 | Igual a |
!= | !=123 | Distinto de |
> | >123 | Mayor que |
>= | >=123 | Mayor o igual que |
< | <123 | Menor que |
<= | <=123 | Menor o igual que |
range:[a..b] | range:[80..120] | Inclusivo en ambos límites |
range:(a..b) | range:(80..120) | Exclusivo en ambos límites |
range:[a..b) | range:[80..120) | Límite inferior inclusivo, superior exclusivo |
range:(a..b] | range:(80..120] | Límite inferior exclusivo, superior inclusivo |
Se admiten enteros, decimales, números negativos y notación científica, p. ej. >=-40, =3.14, o range:[1.5e+35..2.0e+35].
Filtro de nombre vs. consulta de nombre
Sección titulada «Filtro de nombre vs. consulta de nombre»Hay dos formas de comparar por nombre, y se comportan de manera diferente:
| Parámetro | Estilo de coincidencia | ¿Se combina con otros filtros? |
|---|---|---|
fieldFilters={"key":"name",...} | Coincidencia por prefijo, sin difusidad | Sí — siempre aplica AND |
searchNameQuery + nameMatch | contains (por defecto) o exact, sin difusidad | Sí — siempre aplica AND |
Usa fieldFilters con key: "name" para una coincidencia por prefijo solo por nombre que se combine bajo las mismas reglas de AND/OR que type o asset-type. Usa searchNameQuery con nameMatch cuando necesites una búsqueda precisa por subcadena o por nombre exacto sin tolerancia difusa — por ejemplo, para validar que un nombre existe de forma literal.
Respuesta
Sección titulada «Respuesta»{ "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 muestra qué campo o propiedad de metadatos coincidió, con el texto coincidente envuelto en <em>. matchKey es un nombre de campo raíz (p. ej. name) o @<metadata-path> para un valor de metadatos o propiedad anidada que coincidió.
Detalles del resaltado
Sección titulada «Detalles del resaltado»Un mismo resultado puede llevar varias entradas en matchedFields — una por cada campo o propiedad de metadatos que coincidió. Por ejemplo, una coincidencia de nombre en fieldFilters combinada con una solicitud de metadataFilters que coincide tanto con el nombre del objeto como con un valor de metadatos de inspección devuelve:
{ "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"}Los fragmentos de resaltado se escapan como HTML antes de insertar los marcadores <em>, así que cualquier <, > o & en el texto coincidente llega como <, > o & en lugar de marcado sin escapar — seguro para renderizar directamente en HTML sin un segundo paso de escape, pero decódalo primero si necesitas el valor en texto plano.
Casos límite
Sección titulada «Casos límite»| Situación | Comportamiento |
|---|---|
| Sin ningún filtro (o todos vacíos) | Devuelve todos los objetos de negocio del twin, hasta limit, sin clasificación (match_all). |
Una clave de fieldFilters no reconocida | Se ignora silenciosamente — el filtro no aporta nada a la consulta, no genera un 400. |
Un valor de metadataFilters/additionalPropertyFilters igual a * o "" | Se omite. Si todos los valores del array values de ese filtro se omiten de esta forma, el filtro sigue exigiendo que el objeto tenga una propiedad en esa clave — se convierte en una comprobación de presencia de clave sin restricción de valor. |
Ejemplos
Sección titulada «Ejemplos»Búsqueda por prefijo de nombre:
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}Búsqueda de nombre que contiene, ordenada por nombre:
GET {api_url}/v1/twin/{contextId}/search?searchNameQuery=Pump&nameMatch=contains&sortBy=name&sortDir=ASCAuthorization: Bearer {access_token}Casos de error
Sección titulada «Casos de error»| Estado | Causa |
|---|---|
400 Bad Request | Un valor de fieldFilters, metadataFilters o additionalPropertyFilters no es JSON válido, o no coincide con la forma { key, values }. |
Ejemplo completo
Sección titulada «Ejemplo completo»Los parámetros de filtro repetidos (varios fieldFilters, metadataFilters o additionalPropertyFilters con distintos valores JSON) no se pueden construir con el params basado en diccionario de requests — un diccionario solo admite un valor por clave. Construye tú mismo la cadena de consulta con urllib.parse.urlencode y una lista de tuplas:
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"])Búsqueda de nodos
Sección titulada «Búsqueda de nodos»GET /v1/nodes/search busca en la jerarquía de nodos de tu organización — divisiones, sitios, carpetas, twins, bibliotecas de activos y archivos de datos — en lugar de en los objetos de negocio dentro de un twin. La organización se resuelve a partir del token de acceso, no se pasa como parámetro.
Parámetros de consulta
Sección titulada «Parámetros de consulta»| Parámetro | Tipo | Notas |
|---|---|---|
nodeTypes | array de DataNodeType | Filtra a uno o más tipos de nodo. Repite el parámetro, p. ej. ?nodeTypes=Site&nodeTypes=Folder. Valores: Organization, Site, Pointcloud, Mesh, SiteFile, Folder, Project, Division, Artifact, DataBundle, Twin, AssetLibrary. |
excludeNodeTypes | array de DataNodeType | Excluye uno o más tipos de nodo. Misma sintaxis de repetición. |
searchNameQuery | string | Filtra por nombre de nodo. |
nameMatch | exact | contains | Modo de coincidencia para searchNameQuery. Por defecto contains. |
parentId | uuid | Solo los hijos directos de este nodo. |
ancestorId | uuid | Descendientes a cualquier profundidad, excluyendo al propio ancestro. Úsalo para contenido anidado bajo un sitio o carpeta; usa parentId solo para hijos directos. |
createdById | uuid | Filtrar por creador. |
createdBefore / createdAfter | timestamp | Estrictamente antes/después. Formato YYYY-MM-DDTHH:mm:ss. |
updatedBefore / updatedAfter | timestamp | Mismo formato. |
bytesStored | entero | Coincidencia exacta. |
minBytesStored / maxBytesStored | entero | Límites inclusivos. |
childrenCount | entero | Coincidencia exacta. |
minChildrenCount / maxChildrenCount | entero | Límites inclusivos. |
includesThumbnail | 'true' | 'false' | Incluye URLs de miniatura firmadas cuando estén disponibles. Por defecto 'false'. |
page | entero | Por defecto 1. |
limit | entero | 1–50, por defecto 20. |
sortBy | name | createdAt | updatedAt | bytesStored | childrenCount | Campo de ordenación. |
sortDir | ASC | DESC | Dirección de ordenación. Por defecto ASC. |
Respuesta
Sección titulada «Respuesta»{ "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}Ejemplos
Sección titulada «Ejemplos»Todos los sitios bajo un nodo ancestro:
GET {api_url}/v1/nodes/search?nodeTypes=Site&ancestorId=d2a1c4b7-3e10-4f2c-9a6b-7c1d8e2f3a45Authorization: Bearer {access_token}Carpetas cuyo nombre empieza por “Archive”, ordenadas por nombre:
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"])Siguiente paso
Sección titulada «Siguiente paso»Para crear recursos bajo un nodo devuelto por la búsqueda de nodos, consulta Creación de un data bundle.