Pesquisando objetos de negócio e nós
A API do RealityConnect expõe duas rotas de pesquisa com escopos diferentes: a pesquisa de objetos de negócio procura dentro de um twin por POIs, zonas, ativos e seus metadados, enquanto a pesquisa de nós procura na hierarquia de nós da sua organização (sites, pastas, twins e arquivos). Ambas as rotas são experimentais e podem mudar.
Endpoints
Seção intitulada “Endpoints”| Método | Caminho | Escopo | Finalidade |
|---|---|---|---|
GET | /v1/twin/{contextId}/search | Basic | Pesquisar objetos de negócio e metadados dentro de um twin |
GET | /v1/nodes/search | ReadHierarchy | Pesquisar na hierarquia de nós da organização |
Pesquisando objetos de negócio
Seção intitulada “Pesquisando objetos de negócio”GET /v1/twin/{contextId}/search pesquisa POIs, zonas, box assets, medições e outros objetos de negócio dentro de um único twin (ou um de seus sites/rascunhos, identificado por contextId), comparando nome, campos reservados, metadados de ativo e propriedades específicas do objeto.
Parâmetros de consulta
Seção intitulada “Parâmetros de consulta”| Parâmetro | Tipo | Notas |
|---|---|---|
fieldFilters | array de objetos JSON | Filtros de chaves reservadas. Veja abaixo. |
metadataFilters | array de objetos JSON | Compara propriedades de metadados de ativo do twin. Veja abaixo. |
additionalPropertyFilters | array de objetos JSON | Compara propriedades específicas do tipo de objeto (ex.: o icon de um POI). Veja abaixo. |
page | inteiro | Positivo, padrão 1. |
limit | inteiro | 1–50, padrão 50. |
searchNameQuery | string | Filtro de nome dedicado, independente do nome em fieldFilters. |
nameMatch | exact | contains | Modo de correspondência para searchNameQuery. Padrão contains. |
createdById | uuid | Filtrar por criador. |
createdBefore / createdAfter | timestamp | Estritamente antes/depois. Formato YYYY-MM-DDTHH:mm:ss (sem fuso horário, sem milissegundos). |
updatedBefore / updatedAfter | timestamp | Mesmo formato. |
sortBy | name | createdAt | updatedAt | Campo de ordenação. |
sortDir | ASC | DESC | Direção de ordenação. |
Filtros
Seção intitulada “Filtros”fieldFilters, metadataFilters e additionalPropertyFilters são enviados cada um como uma string de objeto JSON por filtro, repetindo o parâmetro de consulta para vários filtros:
?fieldFilters={"key":"type","values":["poi"]}&fieldFilters={"key":"type","values":["zone"]}Cada objeto de filtro tem a forma { "key": string, "values": string[] }. Vários valores no array values de um mesmo filtro são combinados com OR.
fieldFilters aceita apenas estas chaves reservadas — qualquer outra chave é silenciosamente ignorada:
| Chave | Compara |
|---|---|
type | Tipo de objeto de negócio. Aceita o valor do enum (Poi, Zone, BoxAsset, CubePrimitive, PlanePrimitive, DistanceMeasure, CoordinateMeasure, DiameterMeasure, SurfaceMeasure, OrthogonalMeasure, Cut, ModelAsset) ou seu token normalizado em kebab-case — uma versão com hifens e em minúsculas do nome PascalCase, ex.: BoxAsset → box-asset. |
asset-type | O tipo de ativo do objeto (mapeado para assetTypeId). Correspondência exata. |
name | Correspondência por prefixo apenas no nome, sem difusão. |
id | Correspondência exata do id do objeto. |
Os valores de fieldFilters são sempre strings simples ou tokens de enum — a sintaxe numérica/de intervalo abaixo não se aplica a eles.
metadataFilters e additionalPropertyFilters referenciam por chave uma propriedade de metadados definida no schema (metadataFilters) ou uma propriedade específica do tipo de objeto que não faz parte dos metadados comuns (additionalPropertyFilters, ex.: o icon de um POI). Cada valor em values suporta:
| Sintaxe do valor | Significado |
|---|---|
| String simples | Correspondência exata. Várias strings simples em values são combinadas com OR. |
* ou string vazia | Ignorado — se for o único valor, o filtro corresponde apenas pela presença da chave. |
=123, !=123, >123, >=123, <123, <=123 | Comparação numérica. Inteiros, decimais e notação científica (ex.: 1.5e+35) são suportados. |
range:[1..10] | Intervalo numérico inclusivo. |
range:(1..10) | Intervalo numérico exclusivo. |
range:[1..10) / range:(1..10] | Limites mistos inclusivo/exclusivo. |
true / false | Apenas em additionalPropertyFilters — compara literalmente uma propriedade booleana. |
Combinando filtros
Seção intitulada “Combinando filtros”fieldFilters, metadataFilters e additionalPropertyFilters combinam-se com semântica AND: um resultado precisa satisfazer cada filtro. Dentro de um único filtro, os valores no seu array values são combinados com OR — assim, dois objetos fieldFilters que compartilham a mesma key funcionam como “qualquer um dos valores corresponde”, enquanto filtros em chaves diferentes (ou em arrays de filtro diferentes) restringem ainda mais o conjunto de resultados.
Filtro de tipo combinado com um intervalo numérico de metadados (POIs com uma pressão de inspeção registrada entre 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 de ativo combinado com um filtro de nome, atualizações mais recentes primeiro:
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}Isso significa: objetos cujo tipo de ativo é pump e cujo nome começa com “vibration”, ordenados pelos mais recentemente atualizados.
Dois fieldFilters na mesma chave (combinados com OR) combinados com um fieldFilters em uma chave diferente (combinado com AND) — POIs ou zonas, restritos ao tipo de ativo 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}Um literal booleano de additionalPropertyFilters combinado com uma correspondência de string em metadataFilters — POIs ativos cujos metadados adjacentes ao ícone registram um status “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}Uma requisição completa combinando todas as três entradas de filtro, um filtro de nome dedicado, um intervalo de datas, paginação e ordenação — mostrando a forma completa da requisição:
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}Ordenação
Seção intitulada “Ordenação”sortBy | Ordena por |
|---|---|
name | Nome do objeto |
createdAt | Timestamp de criação |
updatedAt | Timestamp da última atualização |
Cada valor de sortBy combina com qualquer valor 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 tem como padrão ASC quando omitido. sortBy não tem um campo padrão documentado — omiti-lo faz a ordenação usar uma pontuação de relevância interna (decrescente), com id (crescente) como critério de desempate. Apenas fieldFilters com key: "name" afeta essa pontuação; qualquer outro filtro é uma correspondência binária (sim/não) sem efeito no ranqueamento, então, na prática, omitir sortBy sem um filtro de name retorna os resultados na ordem de id. Isso é um detalhe de implementação, não um contrato garantido — defina sortBy explicitamente sempre que uma ordem de campo específica for importante para a sua integração.
Filtros numéricos e de intervalo
Seção intitulada “Filtros numéricos e de intervalo”Dentro dos valores de metadataFilters e additionalPropertyFilters, um valor pode carregar um operador de comparação ou um intervalo em vez de corresponder literalmente. Essa sintaxe não se aplica a fieldFilters — esses são sempre correspondência literal/enum (type, asset-type, name, id).
| Operador | Exemplo | Significado |
|---|---|---|
= | =123 | Igual a |
!= | !=123 | Diferente de |
> | >123 | Maior que |
>= | >=123 | Maior ou igual a |
< | <123 | Menor que |
<= | <=123 | Menor ou igual a |
range:[a..b] | range:[80..120] | Inclusivo em ambos os limites |
range:(a..b) | range:(80..120) | Exclusivo em ambos os limites |
range:[a..b) | range:[80..120) | Inclusivo no limite inferior, exclusivo no superior |
range:(a..b] | range:(80..120] | Exclusivo no limite inferior, inclusivo no superior |
Inteiros, decimais, números negativos e notação científica são todos suportados, ex.: >=-40, =3.14, ou range:[1.5e+35..2.0e+35].
Filtro de nome vs. consulta de nome
Seção intitulada “Filtro de nome vs. consulta de nome”Existem duas formas de comparar por nome, e elas se comportam de maneira diferente:
| Parâmetro | Estilo de correspondência | Combina com outros filtros? |
|---|---|---|
fieldFilters={"key":"name",...} | Correspondência por prefixo, sem difusão | Sim — sempre combina com AND |
searchNameQuery + nameMatch | contains (padrão) ou exact, sem difusão | Sim — sempre combina com AND |
Use fieldFilters com key: "name" para uma correspondência por prefixo apenas de nome, que se combina sob as mesmas regras AND/OR que type ou asset-type. Use searchNameQuery com nameMatch quando precisar de uma busca precisa por substring ou por nome exato sem tolerância a difusão — por exemplo, para validar que um nome existe literalmente.
Resposta
Seção intitulada “Resposta”{ "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 qual campo ou propriedade de metadados correspondeu, com o texto correspondido envolvido em <em>. matchKey é um nome de campo raiz (ex.: name) ou @<metadata-path> para um valor de metadados ou propriedade aninhada que correspondeu.
Detalhes do destaque (highlighting)
Seção intitulada “Detalhes do destaque (highlighting)”Um único resultado pode carregar várias entradas em matchedFields — uma para cada campo ou propriedade de metadados que correspondeu. Por exemplo, uma requisição combinada de correspondência de nome via fieldFilters e metadataFilters que corresponde tanto ao nome do objeto quanto a um valor de metadados de inspeção retorna:
{ "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"}Os fragmentos de destaque têm o HTML escapado antes que os marcadores <em> sejam inseridos, então qualquer <, > ou & no texto correspondido chega como <, > ou & em vez de markup bruto — seguro para renderizar diretamente em HTML sem uma segunda passagem de escape, mas decodifique-o primeiro se precisar do valor em texto simples.
Casos extremos
Seção intitulada “Casos extremos”| Situação | Comportamento |
|---|---|
| Nenhum filtro (ou todos vazios) | Retorna todos os objetos de negócio do twin, até o limit, sem ranqueamento (match_all). |
Uma chave de fieldFilters não reconhecida | Silenciosamente ignorada — o filtro não contribui em nada para a consulta, não gera um 400. |
Um valor de metadataFilters/additionalPropertyFilters igual a * ou "" | Ignorado. Se todos os valores no array values desse filtro forem ignorados dessa forma, o filtro ainda exige que o objeto tenha uma propriedade nessa chave — tornando-se uma verificação de presença de chave sem restrição de valor. |
Exemplos
Seção intitulada “Exemplos”Busca por prefixo de 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}Busca por conteúdo de nome ordenada por nome:
GET {api_url}/v1/twin/{contextId}/search?searchNameQuery=Pump&nameMatch=contains&sortBy=name&sortDir=ASCAuthorization: Bearer {access_token}Casos de erro
Seção intitulada “Casos de erro”| Status | Causa |
|---|---|
400 Bad Request | Um valor de fieldFilters, metadataFilters ou additionalPropertyFilters não é um JSON válido, ou não corresponde à forma { key, values }. |
Exemplo completo
Seção intitulada “Exemplo completo”Parâmetros de filtro repetidos (vários fieldFilters, metadataFilters ou additionalPropertyFilters com valores JSON diferentes) não podem ser construídos com o params baseado em dicionário do requests — um dicionário só admite um valor por chave. Construa você mesmo a query string com urllib.parse.urlencode e uma 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"])Pesquisando nós
Seção intitulada “Pesquisando nós”GET /v1/nodes/search pesquisa na hierarquia de nós da sua organização — divisões, sites, pastas, twins, bibliotecas de ativos e arquivos de dados — em vez dos objetos de negócio dentro de um twin. A organização é resolvida a partir do token de acesso, não passada como parâmetro.
Parâmetros de consulta
Seção intitulada “Parâmetros de consulta”| Parâmetro | Tipo | Notas |
|---|---|---|
nodeTypes | array de DataNodeType | Filtra para um ou mais tipos de nó. Repita o parâmetro, ex.: ?nodeTypes=Site&nodeTypes=Folder. Valores: Organization, Site, Pointcloud, Mesh, SiteFile, Folder, Project, Division, Artifact, DataBundle, Twin, AssetLibrary. |
excludeNodeTypes | array de DataNodeType | Exclui um ou mais tipos de nó. Mesma sintaxe de repetição. |
searchNameQuery | string | Filtra por nome do nó. |
nameMatch | exact | contains | Modo de correspondência para searchNameQuery. Padrão contains. |
parentId | uuid | Apenas filhos diretos deste nó. |
ancestorId | uuid | Descendentes em qualquer profundidade, excluindo o próprio ancestral. Use para conteúdo aninhado sob um site ou pasta; use parentId apenas para filhos diretos. |
createdById | uuid | Filtrar por criador. |
createdBefore / createdAfter | timestamp | Estritamente antes/depois. Formato YYYY-MM-DDTHH:mm:ss. |
updatedBefore / updatedAfter | timestamp | Mesmo formato. |
bytesStored | inteiro | Correspondência exata. |
minBytesStored / maxBytesStored | inteiro | Limites inclusivos. |
childrenCount | inteiro | Correspondência exata. |
minChildrenCount / maxChildrenCount | inteiro | Limites inclusivos. |
includesThumbnail | 'true' | 'false' | Inclui URLs de miniatura assinadas quando disponíveis. Padrão 'false'. |
page | inteiro | Padrão 1. |
limit | inteiro | 1–50, padrão 20. |
sortBy | name | createdAt | updatedAt | bytesStored | childrenCount | Campo de ordenação. |
sortDir | ASC | DESC | Direção de ordenação. Padrão ASC. |
Resposta
Seção intitulada “Resposta”{ "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}Exemplos
Seção intitulada “Exemplos”Todos os sites sob um nó ancestral:
GET {api_url}/v1/nodes/search?nodeTypes=Site&ancestorId=d2a1c4b7-3e10-4f2c-9a6b-7c1d8e2f3a45Authorization: Bearer {access_token}Pastas cujo nome começa com “Archive”, ordenadas por 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"])Próximo passo
Seção intitulada “Próximo passo”Para criar recursos sob um nó retornado pela pesquisa de nós, consulte Criando um data bundle.