Partilhar via


O que são expressões de caminho jq no processador de dados?

Importante

Azure IoT Operations Preview – habilitado pelo Azure Arc está atualmente em visualização. Não deve utilizar este software de pré-visualização em ambientes de produção.

Você precisará implantar uma nova instalação do Azure IoT Operations quando uma versão disponível em geral for disponibilizada, você não poderá atualizar uma instalação de visualização.

Veja Termos de Utilização Complementares da Pré-visualizações do Microsoft Azure para obter os termos legais que se aplicam às funcionalidades do Azure que estão na versão beta, na pré-visualização ou que ainda não foram lançadas para disponibilidade geral.

Muitos estágios de pipeline no processador de dados usam expressões de caminho jq. Sempre que precisar recuperar informações de uma mensagem ou colocar alguma informação em uma mensagem, você usa um caminho. Os caminhos JQ permitem-lhe:

  • Localize uma informação em uma mensagem.
  • Identifique onde colocar uma informação em uma mensagem.

Ambos os casos usam a mesma sintaxe e especificam locais relativos à raiz da estrutura da mensagem.

Os caminhos jq suportados pelo processador de dados são sintaticamente corretos para jq, mas têm semântica simplificada para torná-los mais fáceis de usar e ajudar a reduzir erros no pipeline do processador de dados. Em particular, o processador de dados não usa a ? sintaxe para suprimir erros de estruturas de dados desalinhadas. Esses erros são automaticamente suprimidos para você ao trabalhar com caminhos.

Exemplos de acesso a dados dentro de um pipeline de processador de dados incluem os inputPath estágios de valor agregado e último conhecido . Use o padrão de acesso a dados sempre que precisar acessar alguns dados em uma mensagem do processador de dados.

A atualização de dados usa a mesma sintaxe que o acesso a dados, mas há alguns comportamentos especiais em cenários de atualização específicos. Exemplos de atualização de dados dentro de um pipeline do processador de dados incluem os outputPath estágios do pipeline de valor agregado e último conhecido. Use o padrão de atualização de dados sempre que precisar colocar o resultado de uma operação na mensagem do processador de dados.

Nota

Uma mensagem do processador de dados contém mais do que apenas o corpo da sua mensagem. Uma mensagem do processador de dados inclui quaisquer propriedades e metadados que você enviou e outras informações relevantes do sistema. A carga primária que contém os dados enviados para o pipeline de processamento é colocada em um payload campo na raiz da mensagem. É por isso que muitos dos exemplos neste guia incluem caminhos que começam com .payload.

Sintaxe

Cada caminho jq consiste em uma sequência de um ou mais dos seguintes segmentos:

  • O caminho da raiz: ..
  • Um campo em um mapa ou objeto que usa um de:
    • .<identifier> para chaves de objeto alfanuméricas. Por exemplo, .temperature.
    • ."<identifier>" para chaves de objeto arbitrárias. Por exemplo, ."asset-id".
    • ["<identifier>"] ou chaves de objeto arbitrárias. Por exemplo, ["asset-id"].
  • Um índice de matriz: [<index>]. Por exemplo,[2].

Os caminhos devem sempre começar com um .arquivo . Mesmo que você tenha uma matriz ou uma chave de mapa complexa no início do seu caminho, deve haver uma . que a precede. Os caminhos .["complex-key"] e .[1].value são válidos. Os caminhos ["complex-key"] e [1].value são inválidos.

Mensagem de exemplo

Os seguintes exemplos de acesso a dados e atualização de dados usam a seguinte mensagem para ilustrar o uso de diferentes expressões de caminho:

{
  "systemProperties": {
    "partitionKey": "slicer-3345",
    "partitionId": 5,
    "timestamp": "2023-01-11T10:02:07Z"
  },
  "qos": 1,
  "topic": "assets/slicer-3345",
  "properties": {
    "responseTopic": "assets/slicer-3345/output",
    "contentType": "application/json"
  },
  "payload": {
    "Timestamp": 1681926048,
    "Payload": {
      "dtmi:com:prod1:slicer3345:humidity": {
        "sourceTimestamp": 1681926048,
        "value": 10
      },
      "dtmi:com:prod1:slicer3345:lineStatus": {
        "sourceTimestamp": 1681926048,
        "value": [1, 5, 2]
      },
      "dtmi:com:prod1:slicer3345:speed": {
        "sourceTimestamp": 1681926048,
        "value": 85
      },
      "dtmi:com:prod1:slicer3345:temperature": {
        "sourceTimestamp": 1681926048,
        "value": 46
      }
    },
    "DataSetWriterName": "slicer-3345",
    "SequenceNumber": 461092
  }
}

Caminho raiz para acesso a dados

O caminho mais básico é o caminho raiz, que aponta para a raiz da mensagem e retorna a mensagem inteira. Dado o seguinte caminho jq:

.

O resultado é:

{
  "systemProperties": {
    "partitionKey": "slicer-3345",
    "partitionId": 5,
    "timestamp": "2023-01-11T10:02:07Z"
  },
  "qos": 1,
  "topic": "assets/slicer-3345",
  "properties": {
    "responseTopic": "assets/slicer-3345/output",
    "contentType": "application/json"
  },
  "payload": {
    "Timestamp": 1681926048,
    "Payload": {
      "dtmi:com:prod1:slicer3345:humidity": {
        "sourceTimestamp": 1681926048,
        "value": 10
      },
      "dtmi:com:prod1:slicer3345:lineStatus": {
        "sourceTimestamp": 1681926048,
        "value": [1, 5, 2]
      },
      "dtmi:com:prod1:slicer3345:speed": {
        "sourceTimestamp": 1681926048,
        "value": 85
      },
      "dtmi:com:prod1:slicer3345:temperature": {
        "sourceTimestamp": 1681926048,
        "value": 46
      }
    },
    "DataSetWriterName": "slicer-3345",
    "SequenceNumber": 461092
  }
}

Identificador simples para acesso aos dados

O próximo caminho mais simples envolve um único identificador, neste caso o payload campo. Dado o seguinte caminho jq:

.payload

Gorjeta

."payload" e .["payload"] também são maneiras válidas de especificar esse caminho. No entanto, 0-9 identificadores que contêm a-zapenas , A-Ze _ não exigem a sintaxe mais complexa.

O resultado é:

{
  "Timestamp": 1681926048,
  "Payload": {
    "dtmi:com:prod1:slicer3345:humidity": {
      "SourceTimestamp": 1681926048,
      "Value": 10
    },
    "dtmi:com:prod1:slicer3345:lineStatus": {
      "SourceTimestamp": 1681926048,
      "Value": [1, 5, 2]
    },
    "dtmi:com:prod1:slicer3345:speed": {
      "SourceTimestamp": 1681926048,
      "Value": 85
    },
    "dtmi:com:prod1:slicer3345:temperature": {
      "SourceTimestamp": 1681926048,
      "Value": 46
    }
  },
  "DataSetWriterName": "slicer-3345",
  "SequenceNumber": 461092
}

Campos aninhados para acesso a dados

Você pode combinar segmentos de caminho para recuperar dados aninhados profundamente na mensagem, como um único valor de folha. Dado um dos seguintes dois caminhos jq:

.payload.Payload.["dtmi:com:prod1:slicer3345:temperature"].Value
.payload.Payload."dtmi:com:prod1:slicer3345:temperature".Value

O resultado é:

46

Elementos de matriz para acesso a dados

Os elementos de matriz funcionam da mesma forma que as chaves de mapa, exceto que você usa um número no lugar de uma cadeia de caracteres no[]. Dado um dos seguintes dois caminhos jq:

.payload.Payload.["dtmi:com:prod1:slicer3345:lineStatus"].Value[1]
.payload.Payload."dtmi:com:prod1:slicer3345:lineStatus".Value[1]

O resultado é:

5

Caminhos inexistentes e inválidos no acesso aos dados

Se um caminho jq identificar um local que não existe ou é incompatível com a estrutura da mensagem, nenhum valor será retornado.

Importante

Alguns estágios de processamento exigem que algum valor esteja presente e podem falhar se nenhum valor for encontrado. Outros são projetados para continuar o processamento normalmente e ignorar a operação solicitada ou executar uma ação diferente se nenhum valor for encontrado no caminho.

Dado o seguinte caminho jq:

.payload[1].temperature

O resultado é:

Sem valor

Caminho raiz para atualização de dados

O caminho mais básico é o caminho raiz, que aponta para a raiz da mensagem e substitui a mensagem inteira. Dado o seguinte novo valor para inserir e caminho jq:

{ "update": "data" }
.

O resultado é:

{ "update": "data" }

As atualizações não são mescladas profundamente com os dados anteriores, mas substituem os dados no nível em que a atualização acontece. Para evitar a substituição de dados, defina o escopo da atualização para o caminho mais refinado que você deseja alterar ou atualize um campo separado para o lado dos dados primários.

Identificador simples para atualização de dados

O próximo caminho mais simples envolve um único identificador, neste caso o payload campo. Dado o seguinte novo valor para inserir e caminho jq:

{ "update": "data" }
.payload

Gorjeta

."payload" e .["payload"] também são maneiras válidas de especificar esse caminho. No entanto, 0-9 identificadores que contêm a-zapenas , A-Ze _ não exigem a sintaxe mais complexa.

O resultado é:

{
  "systemProperties": {
    "partitionKey": "slicer-3345",
    "partitionId": 5,
    "timestamp": "2023-01-11T10:02:07Z"
  },
  "qos": 1,
  "topic": "assets/slicer-3345",
  "properties": {
    "responseTopic": "assets/slicer-3345/output",
    "contentType": "application/json"
  },
  "payload": { "update": "data" }
}

Campos aninhados para atualização de dados

Você pode combinar segmentos de caminho para recuperar dados aninhados profundamente na mensagem, como um único valor de folha. Dado o seguinte novo valor para inserir e um dos dois caminhos jq a seguir:

{ "update": "data" }
.payload.Payload.["dtmi:com:prod1:slicer3345:temperature"].Value
.payload.Payload."dtmi:com:prod1:slicer3345:temperature".Value

O resultado é:

{
  "systemProperties": {
    "partitionKey": "slicer-3345",
    "partitionId": 5,
    "timestamp": "2023-01-11T10:02:07Z"
  },
  "qos": 1,
  "topic": "assets/slicer-3345",
  "properties": {
    "responseTopic": "assets/slicer-3345/output",
    "contentType": "application/json"
  },
  "payload": {
    "Timestamp": 1681926048,
    "Payload": {
      "dtmi:com:prod1:slicer3345:humidity": {
        "sourceTimestamp": 1681926048,
        "value": 10
      },
      "dtmi:com:prod1:slicer3345:lineStatus": {
        "sourceTimestamp": 1681926048,
        "value": [1, 5, 2]
      },
      "dtmi:com:prod1:slicer3345:speed": {
        "sourceTimestamp": 1681926048,
        "value": 85
      },
      "dtmi:com:prod1:slicer3345:temperature": {
        "sourceTimestamp": 1681926048,
        "value": { "update": "data" }
      }
    },
    "DataSetWriterName": "slicer-3345",
    "SequenceNumber": 461092
  }
}

Elementos de matriz para atualização de dados

Os elementos de matriz funcionam da mesma forma que as chaves de mapa, exceto que você usa um número no lugar de uma cadeia de caracteres no[]. Dado o seguinte novo valor para inserir e um dos dois caminhos jq a seguir:

{ "update": "data" }
.payload.Payload.["dtmi:com:prod1:slicer3345:lineStatus"].Value[1]
.payload.Payload."dtmi:com:prod1:slicer3345:lineStatus".Value[1]

O resultado é:

{
  "systemProperties": {
    "partitionKey": "slicer-3345",
    "partitionId": 5,
    "timestamp": "2023-01-11T10:02:07Z"
  },
  "qos": 1,
  "topic": "assets/slicer-3345",
  "properties": {
    "responseTopic": "assets/slicer-3345/output",
    "contentType": "application/json"
  },
  "payload": {
    "Timestamp": 1681926048,
    "Payload": {
      "dtmi:com:prod1:slicer3345:humidity": {
        "sourceTimestamp": 1681926048,
        "value": 10
      },
      "dtmi:com:prod1:slicer3345:lineStatus": {
        "sourceTimestamp": 1681926048,
        "value": [1, { "update": "data" }, 2]
      },
      "dtmi:com:prod1:slicer3345:speed": {
        "sourceTimestamp": 1681926048,
        "value": 85
      },
      "dtmi:com:prod1:slicer3345:temperature": {
        "sourceTimestamp": 1681926048,
        "value": 46
      }
    },
    "DataSetWriterName": "slicer-3345",
    "SequenceNumber": 461092
  }
}

Caminhos inexistentes e incompatíveis na atualização de dados

Se um caminho jq identificar um local que não existe ou é incompatível com a estrutura da mensagem, então a seguinte semântica se aplica:

  • Se algum segmento do caminho não existir, ele será criado:
    • Para chaves de objeto, a chave é adicionada ao objeto.
    • Para índices de matriz, a matriz é alongada com null valores para torná-la longa o suficiente para ter o índice necessário e, em seguida, o índice é atualizado.
    • Para índices de matriz negativos, o mesmo procedimento de alongamento acontece, mas o primeiro elemento é substituído.
  • Se um segmento de caminho tiver um tipo diferente do necessário, a expressão alterará o tipo e descartará quaisquer dados existentes nesse local de caminho.

Os exemplos a seguir usam a mesma mensagem de entrada que os exemplos anteriores e inserem o seguinte novo valor:

{ "update": "data" }

Dado o seguinte caminho jq:

.payload[1].temperature

O resultado é:

{
  "systemProperties": {
    "partitionKey": "slicer-3345",
    "partitionId": 5,
    "timestamp": "2023-01-11T10:02:07Z"
  },
  "qos": 1,
  "topic": "assets/slicer-3345",
  "properties": {
    "responseTopic": "assets/slicer-3345/output",
    "contentType": "application/json"
  },
  "payload": [null, { "update": "data" }]
}

Dado o seguinte caminho jq:

.payload.nested.additional.data

O resultado é:

{
  "systemProperties": {
    "partitionKey": "slicer-3345",
    "partitionId": 5,
    "timestamp": "2023-01-11T10:02:07Z"
  },
  "qos": 1,
  "topic": "assets/slicer-3345",
  "properties": {
    "responseTopic": "assets/slicer-3345/output",
    "contentType": "application/json"
  },
  "payload": {
    "Timestamp": 1681926048,
    "Payload": {
      "dtmi:com:prod1:slicer3345:humidity": {
        "sourceTimestamp": 1681926048,
        "value": 10
      },
      "dtmi:com:prod1:slicer3345:lineStatus": {
        "sourceTimestamp": 1681926048,
        "value": [1, 5, 2]
      },
      "dtmi:com:prod1:slicer3345:speed": {
        "sourceTimestamp": 1681926048,
        "value": 85
      },
      "dtmi:com:prod1:slicer3345:temperature": {
        "sourceTimestamp": 1681926048,
        "value": 46
      }
    },
    "DataSetWriterName": "slicer-3345",
    "SequenceNumber": 461092,
    "nested": {
      "additional": {
        "data": { "update": "data" }
      }
    }
  }
}

Dado o seguinte caminho jq:

.systemProperties.partitionKey[-4]

O resultado é:

{
  "systemProperties": {
    "partitionKey": [{"update": "data"}, null, null, null],
    "partitionId": 5,
    "timestamp": "2023-01-11T10:02:07Z"
  },
  "qos": 1,
  "topic": "assets/slicer-3345",
  "properties": {
    "responseTopic": "assets/slicer-3345/output",
    "contentType": "application/json"
  },
  "payload": {
    "Timestamp": 1681926048,
    "Payload": {
      "dtmi:com:prod1:slicer3345:humidity": {
        "sourceTimestamp": 1681926048,
        "value": 10
      },
      "dtmi:com:prod1:slicer3345:lineStatus": {
        "sourceTimestamp": 1681926048,
        "value": [1, 5, 2]
      },
      "dtmi:com:prod1:slicer3345:speed": {
        "sourceTimestamp": 1681926048,
        "value": 85
      },
      "dtmi:com:prod1:slicer3345:temperature": {
        "sourceTimestamp": 1681926048,
        "value": 46
      }
    },
    "DataSetWriterName": "slicer-3345",
    "SequenceNumber": 461092,
  }