Compartir vía


¿Qué son las expresiones de ruta de acceso jq en el procesador de datos?

Importante

Operaciones de IoT de Azure, habilitado por Azure Arc, está actualmente en VERSIÓN PRELIMINAR. No se debería usar este software en versión preliminar en entornos de producción.

Tendrá que implementar una nueva instalación de Azure IoT Operations cuando esté disponible una versión disponible con carácter general, no podrá actualizar una instalación en versión preliminar.

Consulte Términos de uso complementarios para las versiones preliminares de Microsoft Azure para conocer los términos legales que se aplican a las características de Azure que se encuentran en la versión beta, en versión preliminar o que todavía no se han publicado para que estén disponibles con carácter general.

Muchas fases de canalización del procesador de datos usan expresiones de ruta de acceso jq. Siempre que necesite recuperar información de un mensaje o colocar alguna información en un mensaje, use una ruta de acceso. Las rutas de acceso jq le permiten:

  • Buscar un fragmento de información en un mensaje.
  • Identificar dónde colocar un fragmento de información en un mensaje.

Ambos casos usan la misma sintaxis y especifican ubicaciones relativas a la raíz de la estructura del mensaje.

Las rutas de acceso jq admitidas por el procesador de datos son sintácticasmente correctas para jq, pero tienen semántica simplificada para facilitar su uso y para ayudar a reducir los errores en la canalización del procesador de datos. En concreto, el procesador de datos no usa la ? sintaxis para suprimir errores de estructuras de datos desalineadas. Esos errores se suprimen automáticamente al trabajar con rutas de acceso.

Entre los ejemplos de acceso a datos dentro de una canalización de procesador de datos se incluye inputPath en las fases de agregado y último valor conocido. Use el patrón de acceso a datos siempre que necesite acceder a algunos datos dentro de un mensaje del procesador de datos.

La actualización de datos usa la misma sintaxis que el acceso a datos, pero hay algunos comportamientos especiales en escenarios de actualización específicos. Entre los ejemplos de actualización a datos dentro de una canalización de procesador de datos se incluye outputPath en las fases de canalización de agregado y último valor conocido. Use el patrón de actualización de datos siempre que necesite colocar el resultado de una operación en el mensaje del procesador de datos.

Nota:

Un mensaje del procesador de datos contiene más que solo el cuerpo del mensaje. Un mensaje del procesador de datos incluye las propiedades y metadatos que envió y otra información pertinente del sistema. La carga principal que contiene los datos enviados a la canalización de procesamiento se coloca en un campo payload en la raíz del mensaje. Este es el motivo por el que muchos de los ejemplos de esta guía incluyen rutas de acceso que comienzan por .payload.

Sintaxis

Cada ruta de acceso jq consta de una secuencia de uno o varios de los siguientes segmentos:

  • Ruta de acceso raíz: ..
  • Campo en un mapa u objeto que usa uno de los siguientes elementos:
    • .<identifier> para las claves de objeto alfanuméricas. Por ejemplo, .temperature.
    • ."<identifier>" para las claves de objeto arbitrarias. Por ejemplo, ."asset-id".
    • ["<identifier>"] o claves de objeto arbitrarias. Por ejemplo, ["asset-id"].
  • Índice de matriz: [<index>]. Por ejemplo, [2].

Las rutas de acceso siempre deben comenzar con .. Incluso si tiene una matriz o una clave de mapa compleja al principio de la ruta de acceso, debe haber un . que lo precede. Las rutas de acceso .["complex-key"] y .[1].value son válidas. Las rutas de acceso ["complex-key"] y [1].value no son válidas.

Mensaje de ejemplo

Los siguientes ejemplos de acceso a datos y actualización de datos usan el siguiente mensaje para ilustrar el uso de expresiones de ruta de acceso diferentes:

{
  "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
  }
}

Ruta de acceso raíz para el acceso a datos

La ruta de acceso más básica es la ruta de acceso raíz, que apunta a la raíz del mensaje y devuelve todo el mensaje. Dada la siguiente ruta de acceso jq:

.

El resultado es el siguiente:

{
  "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 simple para el acceso a datos

La siguiente ruta de acceso más sencilla implica un único identificador, en este caso el campo payload. Dada la siguiente ruta de acceso jq:

.payload

Sugerencia

."payload" y .["payload"] también son formas válidas de especificar esta ruta de acceso. Sin embargo, los identificadores que solo contienen a-z, A-Z, 0-9 y _ no requieren la sintaxis más compleja.

El resultado es el siguiente:

{
  "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 anidados para el acceso a datos

Puede combinar segmentos de línea para recuperar datos anidados profundamente dentro del mensaje, como un solo valor de hoja. Dada cualquiera de las dos rutas de acceso jq siguientes:

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

El resultado es el siguiente:

46

Elementos de matriz para el acceso a datos

Los elementos de matriz funcionan de la misma manera que las claves de asignación, salvo que se usa un número en el lugar de una cadena en []. Dada cualquiera de las dos rutas de acceso jq siguientes:

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

El resultado es el siguiente:

5

Rutas de acceso inexistentes y no válidas en el acceso a datos

Si una ruta de acceso jq identifica una ubicación que no existe o no es compatible con la estructura del mensaje, no se devuelve ningún valor.

Importante

Algunas fases de procesamiento requieren que algún valor esté presente y se puede producir un error si no se encuentra ningún valor. Otras están diseñadas para seguir procesando normalmente y omitir la operación solicitada o realizar una acción diferente si no se encuentra ningún valor en la ruta de acceso.

Dada la siguiente ruta de acceso jq:

.payload[1].temperature

El resultado es el siguiente:

No hay ningún valor

Ruta de acceso raíz para la actualización de datos

La ruta de acceso más básica es la ruta de acceso raíz, que apunta a la raíz del mensaje y reemplaza todo el mensaje. Dado el siguiente nuevo valor para insertar y la ruta de acceso jq:

{ "update": "data" }
.

El resultado es el siguiente:

{ "update": "data" }

Las actualizaciones no se combinan en profundidad con los datos anteriores, sino que reemplazan los datos en el nivel en el que se produce la actualización. Para evitar sobrescribir datos, determine el ámbito de la actualización a la ruta de acceso más detallada que desea cambiar o actualice un campo independiente al lado de los datos principales.

Identificador simple para la actualización de datos

La siguiente ruta de acceso más sencilla implica un único identificador, en este caso el campo payload. Dado el siguiente nuevo valor para insertar y la ruta de acceso jq:

{ "update": "data" }
.payload

Sugerencia

."payload" y .["payload"] también son formas válidas de especificar esta ruta de acceso. Sin embargo, los identificadores que solo contienen a-z, A-Z, 0-9 y _ no requieren la sintaxis más compleja.

El resultado es el siguiente:

{
  "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 anidados para la actualización de datos

Puede combinar segmentos de línea para recuperar datos anidados profundamente dentro del mensaje, como un solo valor de hoja. Dado el siguiente nuevo valor para insertar y cualquiera de las dos rutas de acceso jq siguientes:

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

El resultado es el siguiente:

{
  "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 la actualización de datos

Los elementos de matriz funcionan de la misma manera que las claves de asignación, salvo que se usa un número en el lugar de una cadena en []. Dado el siguiente nuevo valor para insertar y cualquiera de las dos rutas de acceso jq siguientes:

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

El resultado es el siguiente:

{
  "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
  }
}

Rutas de acceso inexistentes y sin coincidencias de tipos en la actualización de datos

Si una ruta de acceso jq identifica una ubicación que no existe o no es compatible con la estructura del mensaje, se aplica la semántica siguiente:

  • Si no existen segmentos de la ruta de acceso, se crean:
    • Para las claves de objeto, la clave se agrega al objeto.
    • En el caso de los índices de matriz, la matriz se alargará con valores null para que sea lo suficientemente larga como para tener el índice necesario y, a continuación, se actualiza el índice.
    • En el caso de los índices de matriz negativos, se produce el mismo procedimiento de alargamiento, pero después se reemplaza el primer elemento.
  • Si un segmento de línea tiene un tipo diferente al que se necesita, la expresión cambia el tipo y descarta los datos existentes en esa ubicación de ruta de acceso.

En los ejemplos siguientes se usa el mismo mensaje de entrada que los ejemplos anteriores y se inserta el siguiente nuevo valor:

{ "update": "data" }

Dada la siguiente ruta de acceso jq:

.payload[1].temperature

El resultado es el siguiente:

{
  "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" }]
}

Dada la siguiente ruta de acceso jq:

.payload.nested.additional.data

El resultado es el siguiente:

{
  "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" }
      }
    }
  }
}

Dada la siguiente ruta de acceso jq:

.systemProperties.partitionKey[-4]

El resultado es el siguiente:

{
  "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,
  }