Referência: JQ Expressions for Digital Twin Adapters
Padrões de expressão JQ práticos para entradas de dispositivo, envelopes de adaptador, condições de rota e mapeamentos de carga útil para normalizar a telemetria no que é definido nos modelos de gêmeos digitais.
Principais Conceitos
Você pode gravar expressões JQ em um adaptador de gêmeo digital como placeholders ${ ... } para calcular valores de destino em payload-mapping e avaliar condições de rota.
Maneiras comuns de usar expressões JQ:
- Entrada do dispositivo: payloads brutos postados por dispositivos.
- Envelope: Declara pontos finais de referência e formas de payload de exemplo; por exemplo, você pode definir o mapeamento
timeObserved. - Rotas: Avalie condições, incluindo pontos finais, cabeçalhos, corpo e selecione um mapeamento de payload.
- Mapeamentos de carga útil: Transforme, converta unidades, renomeie chaves e normalize para o esquema de modelo DTDL.
- Saída: A saída JSON normalizada que deve atender à validação de modelo duplo digital, incluindo tipos, intervalos e unidades.
- Suporte à função de mapeamento: As funções aritmética e
floorsão aceitas. Não há suporte para funções comotoIntegerenumber. - Correspondência de ponto final: Usa condições baseadas em segmento com
endpoint(n), por exemplo:${endpoint(1) == 'home' and endpoint(2) == 'sonnen' and endpoint(3) == 'status'}em vez de padrões curinga não suportados. - Esquema inteiro x duplo:
- Para
schema: "integer", certifique-se de que o mapeamento emite números integrais (por exemplo,"${(.velocity_kph / 1.609) | floor}"). - Para
schema: "double", saídas fracionárias são aceitas; usefloorsomente se quiser o armazenamento de números inteiros como duplo, por exemplo, 68.0.
- Para
- Tipo de conversão suave: Strings numéricas e duplas de números inteiros são aceitas quando correspondem ao tipo de modelo (por exemplo, inteiro). Os auxiliares de conversão como
number()etoIntegerpermanecem sem suporte em expressões de rota; confie em aritmética efloorou adoteschema: "double"para preservar frações.- Pass-through (mph, schema "integer"):
{"speed": "60"}e{"speed": 60.0}são armazenados como60.{"speed": "60.2"}é rejeitado, a menos que o mapeamento gere um inteiro, por exemplo, comfloor. - Rota de métrica (kph → mph):
{"velocity_kph": 110}→68;{"velocity_kph": "110"}→68porque o mapeamentoflooremite um inteiro. Mantenha entradas aritméticas numéricas para evitar erros de expressão; sempre que possível, prefira110em vez de"110". - Arredondamento permanece explícito: A conversão suave não arredonda automaticamente
68.35para68. Usefloorpara esquema de número inteiro ou alterne o modelo paraschema: "double"para preservar frações.
- Pass-through (mph, schema "integer"):
- Tratamento de envelope e tempo: Se o
timeObservednão for fornecido, a plataforma poderá usarreceivedTime. Usefromdateformat,todateformate funções relacionadas para conversões de tempo em mapeamentos de envelope ou payload.
A validação de dados acontece no seu modelo DTDL. Se uma propriedade for declarada como
integer, a saída normalizada deverá ser um valor integer, não um string ou float. Consulte o padrão de correção de número inteiro abaixo.Para obter mais informações, consulte Referência de Extensão de Validação DTMI
Exemplos de entrada de dispositivo
Payloads de entrada típicos com esquemas específicos da unidade:
Unidades padrão dos EUA milhas por hora:
{
"speed": 60
}Unidades métricas europeias quilómetros por hora:
{
"velocity_kph": 110
}
Payload aninhado de um sensor:
{
"telemetry": { "temp_c": 22.4, "humidity": 48 }
}
Matriz de amostras:
{
"samples": [ { "kph": 30 }, { "kph": 50 }, { "kph": 0 } ]
}Estes exemplos mostram um modelo DTDL onde a temperatura é um inteiro dentro do intervalo de 0-100 e umidade é opcional.
{ "temperature": 60, "humidity": 45 }{
"humidity": 45
}{
“temperature”: null
“humidity”: 45
}Mapeamento de envelope
O envelope.json declara um referenceEndpoint e um referencePayload. Opcionalmente, um mapeamento de envelope pode definir time-observed:
{
"referenceEndpoint": "telemetry/automotive/standard",
"referencePayload": {
"dataFormat": "JSON",
"data": { "speed": 65 }
}
}
O identificador especial
receivedTime pode ser fornecido pela plataforma quando o dispositivo omite time. Se o mapeamento de envelope for especificado e contiver um timeObserved, receivedTime será usado como valor timeObserved. Padrões de condição de rota
Condições de roteamento são regras ou expressões usadas para determinar qual regra de mapeamento ou processamento deve ser aplicada a uma mensagem ou solicitação de entrada. Se uma condição de rota for avaliada como verdadeira, a regra de mapeamento ou transformação associada será acionada e aplicada.
Neste exemplo, a condição de rota adaptador duplo digital define duas rotas para processar mensagens de dispositivo de entrada, com base no formato dos dados, por exemplo, se unidades de métrica forem recebidas no 3º segmento do caminho do ponto final, /vehicle/speed/metric-units/
[
{
"description": "European metric to mph; convert then floor (no explicit cast).",
"condition": "${endpoint(3) == \"metric-units\"}",
"payloadMapping": {
"$.speed": "${(.velocity_kph / 1.609) | floor}"
},
"referencePayload": {
"dataFormat": "JSON",
"data": { "velocity_kph": 104 }
}
},
{
"description": "USA standard units passthrough.",
"condition": "*",
"payloadMapping": { "$.speed": "$.speed" }
}
]
endpoint(n)seleciona o segmento de caminhon-th(com base em 0 ou 1, dependendo do adaptador). No cenário de normalização de unidades de medida,endpoint(3)é usado para que/vehicle/speed/metric-units/corresponda ao terceiro segmentometric-units.- Coloque condições mais específicas antes do catch-all
"*". payloadMapping:- Obtém a velocidade do campo
velocity_kphem quilômetros por hora do payload e a converte em milhas por hora:.velocity_kph / 1.609 - Aplica
floorpara arredondar para baixo para o inteiro mais próximofloornão é convertido, portanto, o resultado pode ser um flutuante. - O resultado é atribuído ao campo de saída
speed.
- Obtém a velocidade do campo
referencePayload:- Demonstra a entrada esperada para esta rota:
{"velocity_kph": 104}
- Demonstra a entrada esperada para esta rota:
- Ponto final de entrada:
/vehicle/speed/metric-units/device123 - Payload de entrada:
{ "velocity_kph": 104 }Mapeamento de saída:{ "speed": 64 } (since 104 / 1.609 = 64.64, floor is 64)
Exemplos de mapeamento de carga útil
Expressões JQ comuns para mapeamentos de payload:
- Pass-through:
"$.speed": "$.speed" - Renomear chave:
"$.speed": "${.velocity_kph}" - Conversão de unidade:
"$.mph": "${.kph / 1.609}" - Piso/teto/rodada:
"${.x | floor}","${.x | ceil}","${.x | round}" - Coalesce/default (dependente de versão):
"${ if .value? then .value else 0 end }" - Conversão de tipo:
- Para o número:
"${.value | tonumber}"(suportatonumberna maioria dos builds) - Para string:
"${.value | tostring}"
Observação
Em um adaptador gêmeo digital IoT, funções de conversão comotoIntegerounumbernão são aceitas noinbound-routes. Você pode usar aritmética comfloordefinido para um esquema inteiro ou usarschema: "double"e formatos de arredondamento para ingestão de dados downstream.inbound-routesdeve ser um JSON válido; as expressões pertencem a strings entre aspas"${ ... }". - Para o número:
- Extração aninhada:
"${.telemetry.temp_c}" - Mapa de matriz:
"${[ .samples[] | .kph / 1.609 | floor ]}" - Condicional:
"${ if .kph > 0 then .kph / 1.609 else 0 end }"
Dependendo da integração do seu adaptador, as expressões entre aspas
"${...}" podem ser serializadas como strings. Quando o mecanismo suporta expressões sem aspas, por exemplo, ${...} como valor bruto, é recomendável que o form emita um número JSON em vez de uma string.Nuances: Tipos inteiros, strings e números calculados
Quando uma propriedade DTDL é schema: "integer", a saída normalizada deve ser do tipo inteiro. Dois modos de falha comuns ao calcular valores:
- Stringificação: Uma expressão entre aspas pode gerar
"68"(string), com falha na validação de inteiros. - Números flutuantes: A aritmética produz
68.0; alguns validadores tratam isso como não inteiro, mesmo que matematicamente integral.
Corrigir padrões:
- Usar somente andar para esquema de inteiro:
"${(.velocity_kph / 1.609) | floor}"para produzir um número integral que satisfaça a digitação de inteiro. - Alternativa: alterne a propriedade de modelo para
schema: "double"para preservar a precisão fracionária ou apliquefloorno mapeamento ao armazenar um número inteiro como um dobro. Arredonde/formate no APEX/SQL conforme necessário.
Exemplos de Mapeamento de Adaptador Gêmeo Digital
Este exemplo normaliza quilômetros por hora (KPH) para milhas por hora (MPH) usando floor (sem conversão).
{
"description": "European auto uses metric units; convert to mph and floor to whole number.",
"condition": "${endpoint(3) == \"metric-units\"}",
"payloadMapping": {
"$.speed": "${(.velocity_kph / 1.609) | floor}"
},
"referencePayload": {
"dataFormat": "JSON",
"data": { "velocity_kph": 104 }
}
}
Exemplo: Pass-through catch-all padrão
{
"description": "English units passthrough.",
"condition": "*",
"payloadMapping": {
"$.speed": "$.speed"
}
}
Exemplo: telemetria aninhada e padrão de coalescência
{
"description": "Extract nested temp; default to 0 when missing.",
"condition": "${endpoint(2) == \"env\"}",
"payload-mapping": {
"$.room_temp_c": "${ if .telemetry.temp_c? then .telemetry.temp_c else 0 end }"
}
}
Exemplo: Normalização de matriz
{
"description": "Normalize kph samples to mph (whole-number mph via floor).",
"condition": "${.samples?}",
"payload-mapping": {
"$.speeds": "${ [ .samples[] | .kph / 1.609 | floor ] }"
}
}
Expectativas de saída vs. validação do modelo
As saídas devem atender aos esquemas e restrições do modelo de gêmeo digital. Para o modelo de unidade automotiva em model.json, consulte Cenário: Normalizando Unidades de Medida usando um Adaptador Digital Twin:
name:speedschema:integerunit:milePerHourminimum:0,maximum:100
speed normalizado deve ser um inteiro dentro de 0,100. Uma string calculada "68" ou um número flutuante 68.0 falhará na validação.
Limitações e dicas
- A disponibilidade do filtro varia: A maioria dos filtros jq principais (
floor,ceil,round,tonumber,tostring,map,select,add) - Digitar emissão: As expressões incorporadas em strings entre aspas podem ser serializadas como strings. Preferir expressões sem aspas brutas se houver suporte para emitir tipos numéricos.
- Tratamento nulo: As operações em
nullpodem produzirnull. Useif .x? then ... else ... endpara padrões defensivos. - Precisão: A aritmética de ponto flutuante pode introduzir artefatos de arredondamento; aplique
roundefloorconforme necessário antes da conversão. - Conversão de inteiro: Em testes observados,
toIntegerenumbernão foram aceitos noinbound-routesno momento da criação do adaptador. Preferir aritmética +floorpara esquema inteiro ou usarschema: "double"e arredondar o formato para baixo.
Aplicando a correção de inteiros ao cenário automotivo
O cenário cria um modelo com um número inteiro speed e roteia payloads de unidade de métrica para o mesmo modelo de gêmeo digital. Sem uma conversão explícita, o valor calculado pode ser rejeitado pela validação devido ao desvio de tipo (string ou número semelhante a flutuante).
Correção usada no cenário:
"$.speed": "${(.velocity_kph / 1.609) | floor}"
Por que é necessário:
- floor garante que o valor seja numerado como um todo, satisfazendo a digitação de inteiros.
- Alternativa: use
schema: "double"para preservar a precisão fracionária e arredondar e formatar a jusante, se necessário.
Ao usar o esquema inteiro, prefira aritmética mais
floor. Para esquema duplo, você pode omitir floor para manter MPH fracionário ou incluí-lo para armazenar um número inteiro MPH como um duplo.Snippets de referência rápida
Exemplos suportados:
- Condição: correspondência de ponto final:
"condition": "${endpoint(3) == \"metric-units\"}" - Mapeamento: repasse:
"$.speed": "$.speed" - Mapeamento: kph → mph (esquema inteiro):
"$.speed": "${(.kph / 1.609) | floor}" - Mapeamento: aninhado:
"$.room_temp_c": "${.telemetry.temp_c}" - Mapeamento: padrão:
"$.value": "${ if .value? then .value else 0 end }" - Transformação de matriz:
"$.list": "${ [ .arr[] | .x | tonumber ] }"
Comportamento do Modelo Inteiro versus Duplo
Esta seção resume como o tipo de esquema de modelo afeta o mapeamento e a validação do adaptador.
- esquema: "integer"
- Tipo: Deve ser um número JSON inteiro que seja integral. Strings como
68ou resultados semelhantes a float68.0podem falhar na validação de inteiros. - Mapeamento: Aritmética é permitida;
flooré suportado. Não há suporte para funções comotoIntegerenumber. - Padrão: Use
"${(.velocity_kph / 1.609) | floor}"para coagir a MPH integral. Essa validação e telemetria aprovada foi aceita comoHTTP 202. - Intervalo: Os valores mínimo e máximo são impostos, por exemplo,
0–100
- Tipo: Deve ser um número JSON inteiro que seja integral. Strings como
schema: "double"- Tipo: Qualquer integral ou fracionária de número JSON é aceita se estiver dentro do intervalo; nenhum arredondamento automático executado pela plataforma.
- Mapeamento: Você pode preservar a precisão fracionária, por exemplo,
"${.velocity_kph / 1.609}", ou também aplicarfloorpara produzir um número inteiro de MPH armazenado como duplo, por exemplo:68.0 - Intervalo: Se definido, mínimo e máximo imposto, por exemplo:
0–100
Resultados de telemetria observados
As seguintes combinações foram validadas de ponta a ponta (HTTP/1.1 202 Accepted):
- Modelo inteiro + mapeamento de piso:
"${(.velocity_kph / 1.609) | floor}"→ aceito - Modelo duplo + mapeamento bruto:
"${.velocity_kph / 1.609}"→ mph fracionário aceito - Modelo duplo + mapeamento de piso:
"${(.velocity_kph / 1.609) | floor}"→ número inteiro mph aceito e armazenado como double
Exemplo de curl (placeholders)
Modelo duplo, valor bruto que é mph fracionário conforme esperado:
curl -i -X POST \
-u "european-auto-raw:secret-or-certificate-ocid" \
-H "Content-Type: application/json" \
"https://device-host/telemetry/automotive/metric-units" \
-d '{ "velocity_kph": 110 }'
Modelo duplo, andar um número inteiro MPH, que é armazenado como duplo:
curl -i -X POST \
-u "european-auto-dfloor:secret-or-certificate-ocid" \
-H "Content-Type: application/json" \
"https://device-host/telemetry/automotive/metric-units" \
-d '{ "velocity_kph": 110 }'
Resposta HTTP esperada para cada caso:
HTTP/1.1 202 Accepted
content-type: text/plain
Accepted
Downstream em considerações de APEX ou SQL
- Com double, a velocidade fracional é preservada. Use o SQL
FLOOR/ROUNDpara exibição de número inteiro:SELECT FLOOR(speed) AS speed_mph FROM ... - Com inteiro, verifique se o mapeamento gera valores integrais (por exemplo, via
floor) para atender à validação.
Nome de usuário e cotações de autorização
No OCI IoT, o uso do nome de usuário de autenticação Básica é igual à instância external-key. Se a instância for criada com aspas incorporadas na chave externa, essas aspas se tornarão parte do nome de usuário necessário e deverão ser enviadas literalmente. Isso muitas vezes causa problemas de cotação de shell.
Melhores práticas: Crie instâncias de gêmeos digitais com chaves externas que não incluam aspas, por exemplo, american-auto Quando você precisar autenticar-se com nomes de usuário entre aspas, construa um cabeçalho Authorization: Basic ... em vez de usar -u para evitar erros de cotação.