AWS Security ChangesHomeSearch

AWS iot: Document per-element @{} substitution for InfluxDB array payloads

Service: iot · 2026-09-27 · Documentation low

File: iot/latest/developerguide/iot-substitution-templates.md

Summary

Added a new section describing the per-element substitution sequence @{field} for AWS IoT InfluxDB rule actions, including its requirements, restrictions (not usable in SQL, other actions, functions, or error actions), and examples mapping array elements to InfluxDB points.

Security assessment

This is feature documentation for a new substitution syntax used in InfluxDB rule actions. It describes functional behavior and constraints (e.g., CreateTopicRule/ReplaceTopicRule failing on misuse) but does not address a vulnerability, credential handling, encryption, or authorization, so it is not security-related.

Evidence

+With AWS IoT, you can use the standard substitution template `${`_expression_`}`. This template resolves one time per message, against the message payload as the device published it, before the rule's SQL statement transforms it. If your message payload is a JSON array, use the per-element sequence `@{`_field_`}` instead. This sequence resolves one time for each element of the payload that the rule's SQL statement produces. The rule action writes one InfluxDB line-protocol point per element. It uses the value from the matching element.

Diff

diff --git a/iot/latest/developerguide/iot-substitution-templates.md b/iot/latest/developerguide/iot-substitution-templates.md
index 8d22e6fd4..3358e013f 100644
--- a//iot/latest/developerguide/iot-substitution-templates.md
+++ b//iot/latest/developerguide/iot-substitution-templates.md
@@ -6,0 +7,2 @@
+Per-element substitution for array payloads in AWS IoT rules
+
@@ -104,0 +107,118 @@ Then this rule publishes the following JSON to `my/iot/topic/republish`, which A
+## Per-element substitution for array payloads in AWS IoT rules
+
+With AWS IoT, you can use the standard substitution template `${`_expression_`}`. This template resolves one time per message, against the message payload as the device published it, before the rule's SQL statement transforms it. If your message payload is a JSON array, use the per-element sequence `@{`_field_`}` instead. This sequence resolves one time for each element of the payload that the rule's SQL statement produces. The rule action writes one InfluxDB line-protocol point per element. It uses the value from the matching element.
+
+###### Note
+
+The two sequences read different payloads, so they can resolve to different values for the same field name. If the rule's SQL statement renames or reshapes fields, inside `@{`_field_`}` you must reference the field name as it appears in the SQL output. If an element doesn't contain the field, the sequence resolves to an empty value. It doesn't fall back to a message-level value, and AWS IoT drops an empty tag value from the line protocol that it writes.
+
+###### Important
+
+The `@{`_field_`}` sequence works only in the AWS IoT InfluxDB rule action configuration. It doesn't work in these places:
+
+  * The rule SQL statement (the SELECT, WHERE, or SET clauses)
+
+  * Any other rule action
+
+  * A function. The sequence can't contain one, such as `@{upper(room)}`. You also can't pass the sequence to a substitution template function, because a single configuration value can't contain both `@{...}` and `${...}`.
+
+  * The rule's error action, even when that error action is an InfluxDB action. The error action runs one time for the message, so it never resolves per element.
+
+
+
+
+If you use it in any of these places, the `CreateTopicRule` and `ReplaceTopicRule` operations fail with an error.
+
+The per-element sequence `@{`_field_`}` has the following requirements:
+
+  * Must reference a single field, such as `@{room}` or `@{meta.sensor_id}`
+
+  * Must not include functions, arithmetic, comparisons, or literals
+
+  * Must appear at most one time in a configuration value
+
+  * Must not appear in the same configuration value as a `${...}` substitution template
+
+  * Must appear in a configuration value, not a key (for example, an InfluxDB tag value but not a tag key)
+
+
+
+
+###### Map array elements to InfluxDB points
+
+In this example, an InfluxDB rule action sets the measurement name (`tableName`) to `@{measurement_type}` and a `location` tag to `@{room}`:
+    
+    
+    {
+      "topicRulePayload": {
+        "sql": "SELECT * FROM 'iot/topic'",
+        "ruleDisabled": false,
+        "awsIotSqlVersion": "2016-03-23",
+        "actions": [
+          {
+            "influxDB": {
+              "destinationArn": "arn:aws:iot:us-east-1:123456789012:ruledestination/influxdb/a1b2c3d4-5678-90ab-cdef-EXAMPLE11111",
+              "roleArn": "arn:aws:iam::123456789012:role/aws_iot_influxdb",
+              "databaseName": "device_metrics",
+              "tableName": "@{measurement_type}",
+              "organization": "my_organization",
+              "tags": {
+                "location": "@{room}"
+              },
+              "timestampUnit": "ms"
+            }
+          }
+        ]
+      }
+    }
+
+The following array payload triggers the rule:
+    
+    
+    [
+        { "measurement_type": "temperature", "room": "kitchen", "value": 5,  "timestamp": 1700000000000 },
+        { "measurement_type": "humidity",    "room": "bedroom", "value": 15, "timestamp": 1700000001000 }
+    ]
+
+The action writes one InfluxDB line-protocol point for each element of the array. Each element resolves `@{measurement_type}` to its own measurement name and `@{room}` to its own `location` tag:
+    
+    
+    temperature,location=kitchen value=5i 1700000000000
+    humidity,location=bedroom value=15i 1700000001000
+
+###### Note
+
+AWS IoT excludes any field that a `@{`_field_`}` sequence references from the field set. AWS IoT uses that field's value as the measurement name or tag value. In this example, `measurement_type` supplies the measurement and `room` supplies the `location` tag. AWS IoT excludes both, so each point keeps only `value` as a field.
+
+The preceding example uses `SELECT *`, so the payload that the action receives matches the payload that the device published. If the SQL statement renames a field, use the name that appears in the SQL output. For example, if the statement includes `room AS location_name`, use `@{location_name}` instead of `@{room}`.
+
+###### Resolve against a payload that the SQL statement produces
+
+The payload that the action receives isn't always the payload that the device published. In this example, the device publishes an object that contains an array of readings:
+    
+    
+    {
+        "device_id": "sensor-1",
+        "readings": [
+            { "measurement_type": "temperature", "room": "kitchen", "value": 5,  "timestamp": 1700000000000 },
+            { "measurement_type": "humidity",    "room": "bedroom", "value": 15, "timestamp": 1700000001000 }
+        ]
+    }
+
+The rule uses `SELECT VALUE` to return the `readings` array as the top-level payload. For more information, see [Output an Array as a top-level object](./iot-rule-sql-version.html#return-array-rule).
+    
+    
+    SELECT VALUE readings FROM 'iot/topic'
+
+The action receives the following array, even though the device published an object. It writes the same two points as the preceding example, because each element still contains `measurement_type`, `room`, and `value`.
+    
+    
+    [
+        { "measurement_type": "temperature", "room": "kitchen", "value": 5,  "timestamp": 1700000000000 },
+        { "measurement_type": "humidity",    "room": "bedroom", "value": 15, "timestamp": 1700000001000 }
+    ]
+
+###### Note
+
+The `device_id` field is in the payload that the device published, but not in the array that the SQL statement produces. For that reason, `@{device_id}` doesn't resolve in this rule. Reference only fields that appear in the elements of the produced array.
+