Partager via


Qu’est-ce que les expressions de chemin jq dans le processeur de données Azure IoT (préversion) ?

Important

Opérations Azure IoT (préversion) – activé parc Azure Arc est actuellement en PRÉVERSION. Vous ne devez pas utiliser ce logiciel en préversion dans des environnements de production.

Pour connaître les conditions juridiques qui s’appliquent aux fonctionnalités Azure en version bêta, en préversion ou plus généralement non encore en disponibilité générale, consultez l’Avenant aux conditions d’utilisation des préversions de Microsoft Azure.

De nombreuses étapes de pipeline dans Azure IoT Data Processor (préversion) utilisent des expressions de chemin jq. Chaque fois que vous devez récupérer des informations à partir d’un message ou placer des informations dans un message, vous utilisez un chemin d’accès. Les chemins jq vous permettent de :

  • Rechercher une information dans un message.
  • Identifier où placer une information dans un message.

Les deux cas utilisent la même syntaxe et spécifient des emplacements par rapport à la racine de la structure de message.

Les chemins jq pris en charge par Data Processor sont correctement synchronisés pour jq, mais disposent d’une sémantique simplifiée pour faciliter leur utilisation et aider à réduire les erreurs dans le pipleline Data Processor. En particulier, Data Processor n’utilise pas la syntaxe ? pour supprimer les erreurs pour les structures de données mal alignées. Ces erreurs vous sont automatiquement supprimées lors de l’utilisation des chemins d’accès.

Parmi les exemples d’accès aux données au sein d’un pipeline Data Processor, citons le inputPath dans les étapes agrégation et dernière valeur connue. Utilisez le modèle d’accès aux données chaque fois que vous avez besoin d’accéder à certaines données au sein d’un message Data Processor.

La mise à jour des données utilise la même syntaxe que l’accès aux données, mais il existe des comportements spéciaux dans certains scénarios de mise à jour spécifiques. Parmi les exemples de mise à jour des données au sein d’un pipeline Data Processor, citons le outputPath dans les étapes de pipeline agrégation et dernière valeur connue. Utilisez le modèle de mise à jour des données chaque fois que vous devez placer le résultat d’une opération dans le message Data Processor.

Remarque

Un message Data Processor contient plus que le corps de votre message. Un message Data Processor inclut toutes les propriétés et métadonnées que vous avez envoyées et d’autres informations système pertinentes. La charge utile principale contenant les données envoyées dans le pipeline de traitement est placée dans un champ payload à la racine du message. C’est pourquoi de nombreux exemples de ce guide incluent des chemins d’accès qui commencent par .payload.

Syntaxe

Chaque chemin jq se compose d’une séquence d’un ou plusieurs des segments suivants :

  • Le chemin d’accès de la racine : ..
  • Un champ d’une carte ou d’un objet qui utilise l’un des éléments suivants :
    • .<identifier> pour les clés d’objet alphanumériques. Par exemple : .temperature.
    • ."<identifier>" pour les clés d’objet arbitraire. Par exemple : ."asset-id".
    • ["<identifier>"] ou les clés d’objet arbitraire. Par exemple : ["asset-id"].
  • Un index de tableau : [<index>]. Par exemple : [2].

Les chemins d’accès doivent toujours commencer par un .. Même si vous disposez d’une clé de tableau ou de carte complexe au début de votre chemin d’accès, il doit être précédé d’un .. Les chemins d’accès .["complex-key"] et .[1].value sont valides. Les chemins d’accès ["complex-key"] et [1].value ne sont pas valides.

Exemple de message

Les exemples suivants d’accès aux données et de mise à jour des données utilisent le message suivant pour illustrer l’utilisation de différentes expressions de chemin d’accès :

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

Chemin d’accès racine pour l’accès aux données

Le chemin d’accès le plus simple est le chemin racine, qui pointe vers la racine du message et retourne l’intégralité du message. En partant du chemin d'accès jp suivant :

.

Le résultat est le suivant :

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

Identificateur simple pour l’accès aux données

Le chemin le plus simple suivant implique un identificateur unique, dans ce cas, le champ payload. En partant du chemin d'accès jp suivant :

.payload

Conseil

."payload" et .["payload"] sont également des méthodes valides pour spécifier ce chemin d’accès. Toutefois, les identificateurs qui contiennent uniquement a-z, A-Z, 0-9 et _ ne nécessitent pas la syntaxe plus complexe.

Le résultat est le suivant :

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

Champs imbriqués pour l’accès aux données

Vous pouvez combiner des segments de chemin d’accès pour récupérer des données imbriquées profondément dans le message, telles qu’une valeur feuille unique. En partant de l’un des deux chemins jq suivants :

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

Le résultat est le suivant :

46

Éléments de tableau pour l’accès aux données

Les éléments de tableau fonctionnent de la même manière que les clés de carte, sauf que vous utilisez un nombre à la place d’une chaîne dans le []. En partant de l’un des deux chemins jq suivants :

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

Le résultat est le suivant :

5

Chemins inexistants et non valides dans l’accès aux données

Si un chemin jq identifie un emplacement qui n’existe pas ou n’est pas compatible avec la structure du message, aucune valeur n’est retournée.

Important

Certaines étapes de traitement nécessitent la présence d’une valeur et peuvent échouer si aucune valeur n’est trouvée. D’autres sont conçues pour continuer à traiter normalement et ignorer l’opération demandée ou effectuer une autre action si aucune valeur n’est trouvée sur le chemin d’accès.

En partant du chemin d'accès jp suivant :

.payload[1].temperature

Le résultat est le suivant :

Aucune valeur

Chemin d’accès racine pour la mise à jour des données

Le chemin d’accès le plus simple est le chemin racine, qui pointe vers la racine du message et remplace l’intégralité du message. En partant de la nouvelle valeur suivante à insérer et du chemin jq :

{ "update": "data" }
.

Le résultat est le suivant :

{ "update": "data" }

Les mises à jour ne sont pas fusionnées avec les données précédentes, mais remplacent plutôt les données au niveau où la mise à jour se produit. Pour éviter de remplacer les données, limitez votre mise à jour au chemin le plus précis que vous souhaitez modifier ou mettez à jour un champ distinct à côté de vos données primaires.

Identificateur simple pour la mise à jour des données

Le chemin le plus simple suivant implique un identificateur unique, dans ce cas, le champ payload. En partant de la nouvelle valeur suivante à insérer et du chemin jq :

{ "update": "data" }
.payload

Conseil

."payload" et .["payload"] sont également des méthodes valides pour spécifier ce chemin d’accès. Toutefois, les identificateurs qui contiennent uniquement a-z, A-Z, 0-9 et _ ne nécessitent pas la syntaxe plus complexe.

Le résultat est le suivant :

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

Champs imbriqués pour la mise à jour des données

Vous pouvez combiner des segments de chemin d’accès pour récupérer des données imbriquées profondément dans le message, telles qu’une valeur feuille unique. En partant de la nouvelle valeur suivante à insérer et de l’un des deux chemins jq suivants :

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

Le résultat est le suivant :

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

Éléments de tableau pour la mise à jour des données

Les éléments de tableau fonctionnent de la même manière que les clés de carte, sauf que vous utilisez un nombre à la place d’une chaîne dans le []. En partant de la nouvelle valeur suivante à insérer et de l’un des deux chemins jq suivants :

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

Le résultat est le suivant :

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

Chemins non existants et de type incompatible dans la mise à jour des données

Si un chemin jq identifie un emplacement qui n’existe pas ou n’est pas compatible avec la structure du message, la sémantique suivante s’applique :

  • Si des segments du chemin d’accès n’existent pas, ils sont créés :
    • Pour les clés d’objet, la clé est ajoutée à l’objet.
    • Pour les index de tableau, le tableau est allongé avec des valeurs null pour qu’il soit suffisamment long pour avoir l’index requis, puis l’index est mis à jour.
    • Pour les index de tableau négatifs, la même procédure de longueur se produit, mais le premier élément est remplacé.
  • Si un segment de chemin d’accès a un type différent de ce dont il a besoin, l’expression modifie le type et ignore toutes les données existantes à cet emplacement de chemin d’accès.

Les exemples suivants utilisent le même message d’entrée que les exemples précédents et insèrent la nouvelle valeur suivante :

{ "update": "data" }

En partant du chemin d'accès jp suivant :

.payload[1].temperature

Le résultat est le suivant :

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

En partant du chemin d'accès jp suivant :

.payload.nested.additional.data

Le résultat est le suivant :

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

En partant du chemin d'accès jp suivant :

.systemProperties.partitionKey[-4]

Le résultat est le suivant :

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