IoT 中心消息路由查询语法

消息路由使用户能够将不同的数据类型(包括设备遥测消息、设备生命周期事件和设备孪生更改事件)路由到各个终结点。 此外,还可以在路由此数据之前对其应用丰富查询,以接收对你而言重要的数据。 本文介绍 IoT 中心消息路由查询语言,并提供一些常见的查询模式。

注意

本文中提到的某些功能(例如云到设备消息传递、设备孪生、设备管理)仅在 IoT 中心的标准层中提供。 有关 IoT 中心基本层和标准/免费层的详细信息,请参阅选择适合你的解决方案的 IoT 中心层

消息路由允许你查询消息属性和消息正文以及设备孪生标记和设备孪生属性。 如果消息正文不是 JSON 格式,消息路由仍然可以路由消息,但无法对消息正文应用查询。 查询描述为布尔表达式,如果表达式计算为 true,则查询会成功并路由所有传入数据;否则查询将失败,并且不会路由传入的数据。 如果表达式的计算结果为 null 或未定义的值,它会被视为布尔 false 值,并在 IoT 中心路由资源日志中生成错误。 查询语法必须正确,才能保存和计算路由。

基于消息属性的查询

IoT 中心为所有设备到云的消息传送定义了常见格式,以便实现跨协议互操作性。 IoT 中心采用以下 JSON 表示形式的消息。 为所有用户添加系统属性并标识消息的内容。 用户可以有选择地向消息添加应用程序属性。 我们建议使用唯一的属性名称,因为 IoT 中心设备到云消息传递不区分大小写。 例如,如果有多个具有相同名称的属性,IoT 中心将仅发送其中一个属性。

{ 
  "message": { 
    "systemProperties": { 
      "contentType": "application/json", 
      "contentEncoding": "UTF-8", 
      "iothub-message-source": "deviceMessages", 
      "iothub-enqueuedtime": "2017-05-08T18:55:31.8514657Z" 
    }, 
    "appProperties": { 
      "processingPath": "{cold | warm | hot}", 
      "verbose": "{true, false}", 
      "severity": 1-5, 
      "testDevice": "{true | false}" 
    }, 
    "body": "{\"Weather\":{\"Temperature\":50}}" 
  } 
} 

系统属性

系统属性有助于识别消息的内容和源,下表描述了其中一些内容和源:

属性 类型​​ 说明
contentType 字符串 用户指定消息的内容类型。 若要允许查询消息正文,此值应设置为 application/JSON
contentEncoding 字符串 用户指定消息的编码类型。 如果 contentType 属性设置为 application/JSON,则允许的值为 UTF-8UTF-16UTF-32
iothub-connection-device-id 字符串 此值由 IoT 中心设置,标识设备的 ID。 若要查询,请使用 $connectionDeviceId
iothub-connection-module-id 字符串 此值由 IoT 中心设置,用于标识边缘模块的 ID。 若要查询,请使用 $connectionModuleId
iothub-enqueuedtime 字符串 此值由 IoT 中心设置,表示 UTC 中消息排入队列的实际时间。 若要查询,请使用 $enqueuedTime
dt-dataschema string 此值是由 IoT 中心对设备到云的消息设置的。 它包含在设备连接中设置的设备型号 ID。 若要查询,请使用 $dt-dataschema
dt-subject string 正在发送设备到云的消息的组件名称。 若要查询,请使用 $dt-subject

有关其他可用系统属性的详细信息,请参阅创建和读取 IoT 中心消息

应用程序属性

应用程序属性是用户定义的字符串,可以添加到消息。 这些字段是可选的。

消息属性查询表达式

对消息系统属性的查询必须以 $ 符号为前缀。 对应用程序属性的查询使用其名称进行访问,而且不应以 $ 符号为前缀。 如果应用程序属性名称以 $ 开头,则 IoT 中心首先将在系统属性中搜索它,如果找不到,则在应用程序属性中搜索。 以下示例演示如何查询系统属性和应用程序属性。

查询系统属性 contentEncoding:

$contentEncoding = 'UTF-8'

查询应用程序属性 processingPath:

processingPath = 'hot'

若要组合这些查询,可以使用布尔表达式和函数:

$contentEncoding = 'UTF-8' AND processingPath = 'hot'

用于设备和模块孪生、作业和消息路由的 IoT 中心查询语言表达式和条件部分提供了支持的运算符和函数的完整列表。

基于消息正文的查询

若要启用对消息正文的查询,消息应采用 JSON 格式和 UTF-8、UTF-16 或 UTF-32 编码。 contentType 系统属性必须为 application/JSONcontentEncoding 系统属性必须为该系统属性支持的 UTF 编码值之一。 如果未指定这些系统属性,IoT 中心不会计算消息正文的查询表达式。

以下 JavaScript 示例演示如何使用格式正确且编码的 JSON 正文创建消息:

var messageBody = JSON.stringify(Object.assign({}, {
    "Weather": {
        "Temperature": 50,
        "Time": "2017-03-09T00:00:00.000Z",
        "PrevTemperatures": [
            20,
            30,
            40
        ],
        "IsEnabled": true,
        "Location": {
            "Street": "One Microsoft Way",
            "City": "Redmond",
            "State": "WA"
        },
        "HistoricalData": [
            {
                "Month": "Feb",
                "Temperature": 40
            },
            {
                "Month": "Jan",
                "Temperature": 30
            }
        ]
    }
}));

// Encode message body using UTF-8  
var messageBytes = Buffer.from(messageBody, "utf8");

var message = new Message(messageBytes);

// Set message body type and content encoding 
message.contentEncoding = "utf-8";
message.contentType = "application/json";

// Add other custom application properties   
message.properties.add("Status", "Active");

deviceClient.sendEvent(message, (err, res) => {
    if (err) console.log('error: ' + err.toString());
    if (res) console.log('status: ' + res.constructor.name);
});

有关 C# 中的消息编码示例,请参阅用于 .NET 的 Azure IoT SDK 中提供的 HubRoutingSample。 此示例与消息路由教程中使用的示例相同。 Program.cs 文件还包含一个名为 ReadOneRowFromFile 的方法,该方法读取其中一个编码的文件,对其进行解码,并将其写回 ASCII,以便你可以阅读它。

消息正文查询表达式

对消息正文的查询需要以 $body 为前缀。 你可以在查询表达式中使用正文引用、正文数组引用或多个正文引用。 查询表达式还可以将正文引用与消息系统属性引用或消息应用程序属性引用组合在一起。 例如,以下示例都是有效的查询表达式:

$body.Weather.HistoricalData[0].Month = 'Feb' 
$body.Weather.Temperature = 50 AND $body.Weather.IsEnabled 
length($body.Weather.Location.State) = 2 
$body.Weather.Temperature = 50 AND processingPath = 'hot'

只能对正文引用中的属性运行查询和函数。 不能对整个正文引用运行查询或函数。 例如,以下查询不受支持,并且将返回 undefined

$body[0] = 'Feb'

若要根据更改内容筛选孪生通知有效负载,请对消息正文运行查询。 例如,若要在 sendFrequency 上发生所需的属性更改且值大于 10 时进行筛选,请执行以下操作:

$body.properties.desired.telemetryConfig.sendFrequency > 10

若要筛选包含属性更改的消息(无论属性值为何),可以使用 is_defined() 函数(当值为基元类型时):

is_defined($body.properties.desired.telemetryConfig.sendFrequency)

基于设备或模块孪生的查询

可通过消息路由查询设备孪生模块孪生标记和属性,它们均为 JSON 对象。 以下示例说明了具有标记和属性的设备孪生:

{
    "tags": { 
        "deploymentLocation": { 
            "building": "43", 
            "floor": "1" 
        } 
    }, 
    "properties": { 
        "desired": { 
            "telemetryConfig": { 
                "sendFrequency": "5m" 
            }, 
            "$metadata" : {...}, 
            "$version": 1 
        }, 
        "reported": { 
            "telemetryConfig": { 
                "sendFrequency": "5m", 
                "status": "success" 
            },
            "batteryLevel": 55, 
            "$metadata" : {...}, 
            "$version": 4 
        } 
    } 
} 

注意

模块不会从其对应的设备继承孪生标记。 对来自设备模块(例如来自 IoT Edge 模块)的消息进行孪生查询时,系统是针对模块孪生而非对应的设备孪生进行查询。

孪生查询表达式

对设备孪生或模块孪生的查询需添加 $twin 前缀。 此外,查询表达式还可将孪生标记或属性引用与正文引用、消息系统属性引用或消息应用程序属性引用组合在一起。 我们建议在标记和属性中使用唯一名称,因为查询不区分大小写。 此项建议适用于设备孪生和模块孪生。 我们还建议避免使用 twin$twinbody$body 作为属性名称。 例如,以下示例都是有效的查询表达式:

$twin.properties.desired.telemetryConfig.sendFrequency = '5m'
$body.Weather.Temperature = 50 AND $twin.properties.desired.telemetryConfig.sendFrequency = '5m'
$twin.tags.deploymentLocation.floor = 1 

限制

路由查询不支持在属性名称、消息正文路径或设备/模块孪生路径中使用空格或以下任何字符:()<>@,;:\"/?={}

后续步骤