Ir al contenido

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.


MétodoRutaAlcancePropósito
GET/v1/twin/{contextId}/searchBasicBuscar objetos de negocio y metadatos dentro de un twin
GET/v1/nodes/searchReadHierarchyBuscar en la jerarquía de nodos de la organización

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ámetroTipoNotas
fieldFiltersarray de objetos JSONFiltros de claves reservadas. Ver más abajo.
metadataFiltersarray de objetos JSONCompara propiedades de metadatos de activo del twin. Ver más abajo.
additionalPropertyFiltersarray de objetos JSONCompara propiedades específicas del tipo de objeto (p. ej. el icon de un POI). Ver más abajo.
pageenteroPositivo, por defecto 1.
limitentero150, por defecto 50.
searchNameQuerystringFiltro de nombre dedicado, independiente del nombre en fieldFilters.
nameMatchexact | containsModo de coincidencia para searchNameQuery. Por defecto contains.
createdByIduuidFiltrar por creador.
createdBefore / createdAftertimestampEstrictamente antes/después. Formato YYYY-MM-DDTHH:mm:ss (sin desfase horario, sin milisegundos).
updatedBefore / updatedAftertimestampMismo formato.
sortByname | createdAt | updatedAtCampo de ordenación.
sortDirASC | DESCDirección de ordenación.

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:

ClaveCompara
typeTipo 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. BoxAssetbox-asset.
asset-typeEl tipo de activo del objeto (se asigna a assetTypeId). Coincidencia exacta.
nameCoincidencia por prefijo solo en el nombre, sin difusidad.
idCoincidencia 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 valorSignificado
String simpleCoincidencia exacta. Varios strings simples en values se combinan con OR.
* o string vacíoSe omite — si es el único valor, el filtro compara solo por la presencia de la clave.
=123, !=123, >123, >=123, <123, <=123Comparació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 / falseSolo en additionalPropertyFilters — compara literalmente una propiedad booleana.

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%7D
Authorization: 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=DESC
Authorization: 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%7D
Authorization: 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%7D
Authorization: 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=DESC
Authorization: Bearer {access_token}
sortByOrdena por
nameNombre del objeto
createdAtMarca de tiempo de creación
updatedAtMarca 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=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 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.

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

OperadorEjemploSignificado
==123Igual a
!=!=123Distinto de
>>123Mayor que
>=>=123Mayor o igual que
<<123Menor que
<=<=123Menor 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].

Hay dos formas de comparar por nombre, y se comportan de manera diferente:

ParámetroEstilo de coincidencia¿Se combina con otros filtros?
fieldFilters={"key":"name",...}Coincidencia por prefijo, sin difusidadSí — siempre aplica AND
searchNameQuery + nameMatchcontains (por defecto) o exact, sin difusidadSí — 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.

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

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

SituaciónComportamiento
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 reconocidaSe 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.

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%7D
Authorization: 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=ASC
Authorization: Bearer {access_token}
EstadoCausa
400 Bad RequestUn valor de fieldFilters, metadataFilters o additionalPropertyFilters no es JSON válido, o no coincide con la forma { key, values }.

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 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 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ámetroTipoNotas
nodeTypesarray de DataNodeTypeFiltra 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.
excludeNodeTypesarray de DataNodeTypeExcluye uno o más tipos de nodo. Misma sintaxis de repetición.
searchNameQuerystringFiltra por nombre de nodo.
nameMatchexact | containsModo de coincidencia para searchNameQuery. Por defecto contains.
parentIduuidSolo los hijos directos de este nodo.
ancestorIduuidDescendientes a cualquier profundidad, excluyendo al propio ancestro. Úsalo para contenido anidado bajo un sitio o carpeta; usa parentId solo para hijos directos.
createdByIduuidFiltrar por creador.
createdBefore / createdAftertimestampEstrictamente antes/después. Formato YYYY-MM-DDTHH:mm:ss.
updatedBefore / updatedAftertimestampMismo formato.
bytesStoredenteroCoincidencia exacta.
minBytesStored / maxBytesStoredenteroLímites inclusivos.
childrenCountenteroCoincidencia exacta.
minChildrenCount / maxChildrenCountenteroLímites inclusivos.
includesThumbnail'true' | 'false'Incluye URLs de miniatura firmadas cuando estén disponibles. Por defecto 'false'.
pageenteroPor defecto 1.
limitentero150, por defecto 20.
sortByname | createdAt | updatedAt | bytesStored | childrenCountCampo de ordenación.
sortDirASC | DESCDirección de ordenación. Por defecto 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
}

Todos los sitios bajo un nodo ancestro:

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

Para crear recursos bajo un nodo devuelto por la búsqueda de nodos, consulta Creación de un data bundle.