次の方法で共有


Azure IoT Data Processor プレビューの jq パス式とは

重要

Azure Arc によって有効にされる Azure IoT Operations Preview は、 現在プレビュー段階です。 運用環境ではこのプレビュー ソフトウェアを使わないでください。

ベータ版、プレビュー版、または一般提供としてまだリリースされていない Azure の機能に適用される法律条項については、「Microsoft Azure プレビューの追加使用条件」を参照してください。

Azure IoT Data Processor プレビューの多くのパイプライン ステージでは、"jq パス" 式が使われます。 メッセージから情報を取得したり、メッセージに情報を配置したりする必要があるときは常に、パスを使います。 jq パスを使うと、次のことができます。

  • メッセージ内の情報を見つけます。
  • メッセージに情報を配置する場所を特定します。

どちらの場合も同じ構文を使い、メッセージ構造のルートを基準にして場所を指定します。

Data Processor でサポートされる jq パスは、jq の構文に関しては正しいものですが、使いやすくし、Data Processor のパイプラインでのエラーを減らすため、セマンティクスが簡略化されています。 具体的には、Data Processor では、データ構造の不整合に関するエラーを抑制する ? 構文は使われません。 これらのエラーは、パスを操作するときは自動的に抑制されます。

Data Processor パイプライン内のデータ アクセスの例には、集計最後の既知の値ステージの inputPath が含まれます。 Data Processor メッセージ内のデータにアクセスする必要がある場合は常に、データ アクセス パターンを使います。

データ更新ではデータ アクセスと同じ構文を使いますが、特定の更新シナリオではいくつかの特別な動作があります。 Data Processor パイプライン内のデータ更新の例には、集計最後の既知の値パイプライン ステージの outputPath が含まれます。 操作の結果を Data Processor メッセージに配置する必要がある場合は常に、データ更新パターンを使います。

Note

Data Processor メッセージには、メッセージの本文以外のものが含まれます。 Data Processor メッセージには、送信したプロパティとメタデータ、およびその他の関連するシステム情報が含まれます。 処理パイプラインに送信されたデータを含むプライマリ ペイロードは、メッセージのルートにある payload フィールドに配置されます。 このため、このガイドの多くの例には、.payload で始まるパスが含まれます。

構文

すべての jq パスは、次のセグメントの 1 つ以上のシーケンスで構成されます。

  • ルート パス: .
  • 次のいずれかを使うマップまたはオブジェクト内のフィールド。
    • 英数字オブジェクト キーの .<identifier>。 たとえば、.temperature のようにします。
    • 任意のオブジェクト キーの ."<identifier>"。 たとえば、."asset-id" のようにします。
    • ["<identifier>"] または任意のオブジェクト キー。 たとえば、["asset-id"] のようにします。
  • 配列インデックス: [<index>]。 例: [2]

パスは常に . で始まる必要があります。 パスの先頭に配列または複合マップ キーがある場合でも、その前に . を付ける必要があります。 .["complex-key"].[1].value は有効なパスです。 ["complex-key"][1].value は無効なパスです。

メッセージ例:

以下のデータ アクセスとデータ更新の例では、次のメッセージを使って、さまざまなパス式の使用方法を示します。

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

データ アクセスの場合のルート パス

最も基本的なパスはルート パスであり、メッセージのルートを指し、メッセージ全体を返します。 次のような jq パスを考えてください。

.

結果は次のとおりです。

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

データ アクセスの場合の単純な識別子

次に最も簡単なパスには、1 つの識別子 (この場合は payload フィールド) が含まれます。 次のような jq パスを考えてください。

.payload

ヒント

."payload".["payload"] も、このパスを指定する有効な方法です。 ただし、a-zA-Z0-9_ のみを含む識別子では、さらに複雑な構文は必要ありません。

結果は次のとおりです。

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

データ アクセスの場合の入れ子になったフィールド

パス セグメントを組み合わせて、単一のリーフ値など、メッセージ内で深く入れ子になったデータを取得できます。 次の 2 つの jq パスのいずれかを考えてください。

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

結果は次のとおりです。

46

データ アクセスの場合の配列要素

配列要素はマップ キーと同じように動作しますが、[] で文字列の代わりに数値を使う点が異なります。 次の 2 つの jq パスのいずれかを考えてください。

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

結果は次のとおりです。

5

データ アクセスでの存在しないパスと無効なパス

jq パスで存在しない場所、またはメッセージの構造と互換性のない場所を指定した場合、値は返されません。

重要

一部の処理ステージでは、何らかの値が存在している必要があり、値が見つからない場合は失敗することがあります。 その他は通常どおり処理を続けるように設計されており、パスに値が見つからない場合は、要求された操作をスキップするか、別のアクションを実行します。

次のような jq パスを考えてください。

.payload[1].temperature

結果は次のとおりです。

値なし

データ更新の場合のルート パス

最も基本的なパスはルート パスであり、メッセージのルートを指し、メッセージ全体を置き換えます。 次のような新しく挿入する値と jq パスを考えてください。

{ "update": "data" }
.

結果は次のとおりです。

{ "update": "data" }

更新は前のデータと深くマージされるのではなく、更新が行われるレベルでデータを置き換えます。 データが上書きされないようにするには、更新のスコープを変更したい最も詳細なパスに設定するか、主要なデータとは異なるフィールドを更新します。

データ更新の場合の単純な識別子

次に最も簡単なパスには、1 つの識別子 (この場合は payload フィールド) が含まれます。 次のような新しく挿入する値と jq パスを考えてください。

{ "update": "data" }
.payload

ヒント

."payload".["payload"] も、このパスを指定する有効な方法です。 ただし、a-zA-Z0-9_ のみを含む識別子では、さらに複雑な構文は必要ありません。

結果は次のとおりです。

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

データ更新の場合の入れ子になったフィールド

パス セグメントを組み合わせて、単一のリーフ値など、メッセージ内で深く入れ子になったデータを取得できます。 次のような新しく挿入する値と 2 つの jq パスのいずれかを考えてください。

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

結果は次のとおりです。

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

データ更新の場合の配列要素

配列要素はマップ キーと同じように動作しますが、[] で文字列の代わりに数値を使う点が異なります。 次のような新しく挿入する値と 2 つの jq パスのいずれかを考えてください。

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

結果は次のとおりです。

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

データ更新での存在しないパスと型が一致しないパス

jq パスで存在しない場所、またはメッセージの構造と互換性のない場所を指定した場合、次のセマンティクスが適用されます。

  • パスのセグメントが存在しない場合は、作成されます。
    • オブジェクト キーの場合、キーがオブジェクトに追加されます。
    • 配列インデックスの場合、必要なインデックスを保持するのに十分な長さになるまで、配列が null 値で延長された後、インデックスが更新されます。
    • 負の配列インデックスの場合、同じ延長手順が実行されますが、最初の要素が置き換えられます。
  • パスのセグメントの型が必要な型と異なる場合は、式によって型が変更されて、そのパスの場所にある既存のデータは破棄されます。

次の例では、前の例と同じ入力メッセージを使って、次の新しい値を挿入します。

{ "update": "data" }

次のような jq パスを考えてください。

.payload[1].temperature

結果は次のとおりです。

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

次のような jq パスを考えてください。

.payload.nested.additional.data

結果は次のとおりです。

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

次のような jq パスを考えてください。

.systemProperties.partitionKey[-4]

結果は次のとおりです。

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