Linguagem de consulta do Hub IoT para gémeos de dispositivos e de módulos, tarefas e encaminhamento de mensagens

O Hub IoT fornece uma poderosa linguagem semelhante ao SQL para recuperar informações sobre gêmeos de dispositivos, gêmeos de módulos, trabalhos e roteamento de mensagens. Este artigo apresenta:

Para exemplos específicos, consulte Consultas para gêmeos de dispositivos e módulos do Hub IoT ou Consultas para trabalhos do Hub IoT.

Nota

Alguns dos recursos mencionados neste artigo, como mensagens de nuvem para dispositivo, gêmeos de dispositivo e gerenciamento de dispositivos, estão disponíveis apenas na camada padrão do Hub IoT. Para obter mais informações sobre as camadas básica e padrão/gratuita do Hub IoT, consulte Escolha a camada e o tamanho certos do Hub IoT para sua solução.

Executar consultas do Hub IoT

Você pode executar consultas em seu hub IoT diretamente no portal do Azure.

  1. Entre no portal do Azure e navegue até seu hub IoT.
  2. Selecione Consultas na seção Gerenciamento de dispositivos do menu de navegação.
  3. Introduza a sua consulta na caixa de texto e selecione Executar consulta.

Você também pode executar consultas em seus aplicativos usando os SDKs e APIs de serviço do Azure IoT.

Por exemplo, para código que implementa consultas do Hub IoT, consulte a secção Exemplos de consultas com os SDKs de serviço.

Para ligações a páginas de referência e exemplos de SDKs, veja Hub IoT do Azure SDKs.

Noções básicas de uma consulta do Hub IoT

Cada consulta do Hub IoT consiste em cláusulas SELECT e FROM, com cláusulas opcionais WHERE e GROUP BY.

As consultas são executadas numa coleção de documentos JSON, por exemplo gémeos de dispositivo. A cláusula FROM indica a coleção de documentos a ser iterada ( devices, devices.modules ou devices.jobs).

Em seguida, o filtro na cláusula WHERE é aplicado. Com agregações, os resultados desta etapa são agrupados conforme especificado na cláusula GROUP BY. Para cada grupo, uma linha é gerada conforme especificado na cláusula SELECT.

SELECT <select_list>
  FROM <from_specification>
  [WHERE <filter_condition>]
  [GROUP BY <group_specification>]

Cláusula SELECT

A cláusula SELECT <select_list> é necessária em todas as consultas Hub IoT. Ele especifica quais valores são recuperados da consulta. Ele especifica os valores JSON a serem usados para gerar novos objetos JSON. Para cada elemento do subconjunto filtrado (e opcionalmente agrupado) da coleção FROM, a fase de projeção gera um novo objeto JSON. Este objeto é construído com os valores especificados na cláusula SELECT.

Por exemplo:

  • Retornar todos os valores

    SELECT *
    
  • Retornar propriedades específicas

    SELECT DeviceID, LastActivityTime
    
  • Agregar os resultados de uma consulta para retornar uma contagem

    SELECT COUNT() as TotalNumber
    

Atualmente, cláusulas de seleção diferentes do SELECT são apenas suportadas em consultas agregadas em gémeos de dispositivos.

A sintaxe a seguir é a gramática da cláusula SELECT:

SELECT [TOP <max number>] <projection list>

<projection_list> ::=
    '*'
    | <projection_element> AS alias [, <projection_element> AS alias]+

<projection_element> :==
    attribute_name
    | <projection_element> '.' attribute_name
    | <aggregate>

<aggregate> :==
    count()
    | avg(<projection_element>)
    | sum(<projection_element>)
    | min(<projection_element>)
    | max(<projection_element>)

Attribute_name refere-se a qualquer propriedade do documento JSON na coleção FROM.

Cláusula FROM

A FROM <from_specification> cláusula é necessária em todas as consultas do ioT Hub. Deve ser um de três valores:

  • dispositivos para interrogar réplicas de dispositivos
  • devices.modules para interrogar geminados de módulos
  • devices.jobs para consultar detalhes de trabalhos por dispositivo

Por exemplo:

  • Recuperar todos os gémeos de dispositivos

    SELECT * FROM devices
    

Cláusula WHERE

A WHERE <filter_condition> cláusula é opcional. Ele especifica uma ou mais condições que os documentos JSON na coleção FROM devem satisfazer para serem incluídos como parte do resultado. Qualquer documento JSON deve avaliar as condições especificadas para serem verdadeiras e incluídas no resultado.

Por exemplo:

  • Recuperar todos os trabalhos que visam um dispositivo específico

    SELECT * FROM devices.jobs
      WHERE devices.jobs.deviceId = 'myDeviceId'
    

As condições permitidas são descritas na secção Expressões e condições .

Cláusula GROUP BY

A GROUP BY <group_specification> cláusula é opcional. Esta cláusula é executada após o filtro especificado na cláusula WHERE e antes da projeção especificada na cláusula SELECT. Ele agrupa documentos com base no valor de um atributo. Esses grupos são usados para gerar valores agregados conforme especificado na cláusula SELECT.

Por exemplo:

  • Retornar a contagem de dispositivos que estão a relatar cada estado de configuração de telemetria.

    SELECT properties.reported.telemetryConfig.status AS status,
      COUNT() AS numberOfDevices
    FROM devices
    GROUP BY properties.reported.telemetryConfig.status
    

Atualmente, a cláusula GROUP BY só é suportada ao consultar gémeos de dispositivo.

Atenção

O termo grupo é atualmente tratado como uma palavra-chave especial nas consultas. Caso use group como nome da propriedade, considere rodeá-lo com dois parênteses para evitar erros, como mostrado neste exemplo: SELECT * FROM devices WHERE tags.[[group]].name = 'some_value'.

A sintaxe formal para GROUP BY é:

GROUP BY <group_by_element>
<group_by_element> :==
    attribute_name
    | < group_by_element > '.' attribute_name

Attribute_name refere-se a qualquer propriedade do documento JSON na coleção FROM.

Paginação dos resultados da consulta

Um objeto de consulta é instanciado com um tamanho máximo de página menor que ou igual a 100 registos. Para obter várias páginas, chame várias vezes o nextAsTwin no SDK Node.js ou o método GetNextAsTwinAsync no SDK .NET. Um objeto de consulta pode expor vários valores Next, dependendo da opção de desserialização exigida pela consulta. Por exemplo, um objeto de consulta pode devolver objetos gémeos de dispositivo ou de trabalho, ou JSON simples ao usar projeções.

Expressões e condições

A um nível geral, uma expressão:

  • Avalia para uma instância de um tipo JSON (como Booleano, número, string, array ou objeto).
  • É definido pela manipulação de dados provenientes do documento JSON do dispositivo e constantes usando operadores e funções incorporadas.

As condições são expressões que são avaliadas como booleano. Qualquer constante diferente de Boolean true é considerada como falsa. Esta regra inclui null, undefined, qualquer objeto ou instância de matriz, qualquer string e o Boolean false.

A sintaxe das expressões é:

<expression> ::=
    <constant> |
    attribute_name |
    <function_call> |
    <expression> binary_operator <expression> |
    <create_array_expression> |
    '(' <expression> ')'

<function_call> ::=
    <function_name> '(' expression ')'

<constant> ::=
    <undefined_constant>
    | <null_constant>
    | <number_constant>
    | <string_constant>
    | <array_constant>

<undefined_constant> ::= undefined
<null_constant> ::= null
<number_constant> ::= decimal_literal | hexadecimal_literal
<string_constant> ::= string_literal
<array_constant> ::= '[' <constant> [, <constant>]+ ']'

Para entender o que significa cada símbolo na sintaxe das expressões, consulte a tabela a seguir:

Símbolo Definição
nome_do_atributo Qualquer propriedade do documento JSON na coleção FROM .
operador binário Qualquer operador binário listado na seção Operadores .
function_name Qualquer função listada na seção Funções .
decimal_literal Um número flutuante expresso em notação decimal.
hexadecimal_literal Número expresso pela cadeia «0x» seguida de uma cadeia de algarismos hexadecimais.
string_literal Cadeias de caracteres Unicode representadas por uma sequência de zero ou mais caracteres Unicode ou sequências de escape. Os literais da cadeia são incluídos entre aspas simples ou duplas. Escapes permitidos: \', \", \\, \uXXXX para caracteres Unicode definidos por quatro dígitos hexadecimais.

Operadores

Os seguintes operadores são suportados:

Família Operadores
Arithmetic +, -, *, /, %
Lógico E, OU, NÃO
Comparação =, !=, <, >, <=, >=, <>

Funções

Ao consultar gémeos e tarefas, a única função suportada é:

Function Descrição
IS_DEFINED(property) Devolve um booleano indicando se a propriedade tem um valor atribuído (incluindo null).

Em condições de rotas, as seguintes funções matemáticas são suportadas:

Function Descrição
ABS(x) Devolve o valor absoluto (positivo) da expressão numérica especificada.
EXP(x) Devolve o valor exponencial da expressão numérica especificada (e^x).
POTÊNCIA (x,y) Retorna o valor da expressão especificada para a potência especificada (x^y).
SQUARE(x) Devolve o quadrado do valor numérico especificado.
CEILING(x) Retorna o menor valor inteiro maior ou igual à expressão numérica especificada.
FLOOR(x) Retorna o maior inteiro menor ou igual à expressão numérica especificada.
SIGN(x) Devolve o sinal positivo (+1), zero (0) ou negativo (-1) da expressão numérica especificada.
SQRT(x) Retorna a raiz quadrada do valor numérico especificado.

Em condições de rota, são suportadas as seguintes funções de verificação de tipos e de lançamento:

Function Descrição
AS_NUMBER Converte a cadeia de caracteres de entrada em um número. noop se a entrada for um número; Undefined se string não representa um número.
IS_ARRAY Retorna um valor booleano que indica se o tipo da expressão especificada é uma matriz.
IS_BOOL Retorna um valor booleano que indica se o tipo da expressão especificada é booleano.
IS_DEFINED Devolve um booleano indicando se a propriedade é um valor. Esta função é suportada apenas quando o valor é um tipo primitivo. Os tipos primitivos incluem string, booleano, numérico ou null. DateTime, tipos de objetos e arrays não são suportados.
IS_NULL Retorna um valor booleano indicando se o tipo da expressão especificada é null.
IS_NUMBER Retorna um valor booleano que indica se o tipo da expressão especificada é um número.
IS_OBJECT Retorna um valor booleano indicando se o tipo da expressão especificada é um objeto JSON.
IS_PRIMITIVE Retorna um valor booleano que indica se o tipo da expressão especificada é uma primitiva (string, booleana, numérica ou null).
IS_STRING Retorna um valor booleano que indica se o tipo da expressão especificada é uma cadeia de caracteres.

Em condições de rotas, as seguintes funções de cadeia de caracteres são suportadas:

Function Descrição
CONCAT(x, y, ...) Retorna uma cadeia de caracteres que é o resultado da concatenação de dois ou mais valores de cadeia de caracteres.
LENGTH(x) Retorna o número de caracteres da expressão de cadeia de caracteres especificada.
LOWER(x) Retorna uma expressão de cadeia de caracteres depois de converter dados de caracteres maiúsculos em minúsculas.
UPPER(x) Retorna uma expressão de cadeia de caracteres depois de converter dados de caracteres minúsculos em maiúsculas.
SUBSTRING(string, início [, comprimento]) Retorna parte de uma expressão de cadeia de caracteres começando na posição baseada em zero do caractere especificado e continua até o comprimento especificado ou até o final da cadeia de caracteres.
INDEX_OF(string, fragmento) Retorna a posição inicial da primeira ocorrência da segunda expressão de cadeia de caracteres dentro da primeira expressão de cadeia de caracteres especificada, ou -1 se a cadeia de caracteres não for encontrada.
COMEÇA_COM(x, y) Retorna um booleano indicando se a primeira expressão de cadeia de caracteres começa com a segunda.
ENDS_WITH(x, y) Retorna um Boolean indicando se a primeira expressão de cadeia de caracteres termina com a segunda.
CONTAINS(x,y) Retorna um Boolean indicando se a primeira expressão de cadeia de caracteres contém a segunda.

Consultar exemplos com os SDKs de serviço

Exemplo de C#

A funcionalidade de consulta é exposta pelo SDK de serviço Hub IoT do Azure para .NET na classe RegistryManager.

Aqui está um exemplo de uma consulta simples:

var query = registryManager.CreateQuery("SELECT * FROM devices", 100);
while (query.HasMoreResults)
{
    var page = await query.GetNextAsTwinAsync();
    foreach (var twin in page)
    {
        // do work on twin object
    }
}

O objeto de consulta é instanciado com os parâmetros mencionados na secção de paginação dos resultados da consulta . Várias páginas são recuperadas ao chamar os GetNextAsTwinAsync métodos várias vezes.

Node.js exemplo

A funcionalidade de consulta é exposta pelo SDK de serviço Hub IoT do Azure para Node.js no objeto Registry.

Aqui está um exemplo de uma consulta simples:

var query = registry.createQuery('SELECT * FROM devices', 100);
var onResults = function(err, results) {
    if (err) {
        console.error('Failed to fetch the results: ' + err.message);
    } else {
        // Do something with the results
        results.forEach(function(twin) {
            console.log(twin.deviceId);
        });

        if (query.hasMoreResults) {
            query.nextAsTwin(onResults);
        }
    }
};
query.nextAsTwin(onResults);

O objeto de consulta é instanciado com os parâmetros mencionados na secção de paginação dos resultados da consulta . Várias páginas são recuperadas ao chamar o nextAsTwin método várias vezes.

Consultas para dispositivos e módulos gémeos Hub IoT

Os gémeos de dispositivo e os gémeos de módulo podem conter objetos JSON arbitrários tanto como etiquetas como propriedades. O Hub IoT permite consultar gêmeos de dispositivos e gêmeos de módulos como um único documento JSON contendo toda a informação dos gêmeos.

Aqui está um exemplo de dispositivo gémeo hub IoT (módulo gémeo seria semelhante, só que com um parâmetro para o moduleId):

{
    "deviceId": "myDeviceId",
    "etag": "AAAAAAAAAAc=",
    "status": "enabled",
    "statusUpdateTime": "0001-01-01T00:00:00",
    "connectionState": "Disconnected",
    "lastActivityTime": "0001-01-01T00:00:00",
    "cloudToDeviceMessageCount": 0,
    "authenticationType": "sas",
    "x509Thumbprint": {
        "primaryThumbprint": null,
        "secondaryThumbprint": null
    },
    "version": 2,
    "tags": {
        "location": {
            "region": "US",
            "plant": "Redmond43"
        }
    },
    "properties": {
        "desired": {
            "telemetryConfig": {
                "configId": "db00ebf5-eeeb-42be-86a1-458cccb69e57",
                "sendFrequencyInSecs": 300
            },
            "$metadata": {
            ...
            },
            "$version": 4
        },
        "reported": {
            "connectivity": {
                "type": "cellular"
            },
            "telemetryConfig": {
                "configId": "db00ebf5-eeeb-42be-86a1-458cccb69e57",
                "sendFrequencyInSecs": 300,
                "status": "Success"
            },
            "$metadata": {
            ...
            },
            "$version": 7
        }
    }
}

Consultas de gémeos de dispositivo

Hub IoT expõe os gémeos de dispositivos como uma coleção de documentos chamada dispositivos. Por exemplo, a consulta mais básica recupera todo o conjunto de gémeos de dispositivo:

SELECT * FROM devices

Nota

Os SDKs Azure IoT suportam a paginação de grandes volumes de resultados.

Pode agregar os resultados de uma consulta usando a cláusula SELECT. Por exemplo, a consulta seguinte obtém uma contagem do número total de dispositivos num hub IoT:

SELECT COUNT() as totalNumberOfDevices FROM devices

Filtrar os resultados da consulta usando a cláusula WHERE. Por exemplo, para receber gémeos de dispositivo onde a location.region etiqueta está definida para US , use a seguinte consulta:

SELECT * FROM devices
WHERE tags.location.region = 'US'

Crie cláusulas WHERE complexas usando operadores booleanos e comparações aritméticas. Por exemplo, a consulta seguinte recupera réplicas de dispositivos localizados nos EUA e configurados para enviar telemetria a intervalos inferiores a um minuto:

SELECT * FROM devices
  WHERE tags.location.region = 'US'
    AND properties.reported.telemetryConfig.sendFrequencyInSecs >= 60

Pode usar também constantes de array com os operadores IN e NIN (não in). Por exemplo, a consulta seguinte recupera gémeos de dispositivos que reportam conectividade WiFi ou por cabo:

SELECT * FROM devices
  WHERE properties.reported.connectivity IN ['wired', 'wifi']

É frequentemente necessário identificar todos os gémeos de dispositivo que contenham uma propriedade específica. Hub IoT suporta a função is_defined() para este fim. Por exemplo, a consulta seguinte recupera gémeos de dispositivos que definem a propriedade connectivity.

SELECT * FROM devices
  WHERE is_defined(properties.reported.connectivity)

Consulte a secção da cláusula WHERE para a referência completa das capacidades de filtragem.

A funcionalidade de agrupamento também é suportada. Por exemplo, a consulta seguinte devolve a contagem de dispositivos em cada estado de configuração de telemetria:

SELECT properties.reported.telemetryConfig.status AS status,
    COUNT() AS numberOfDevices
  FROM devices
  GROUP BY properties.reported.telemetryConfig.status

Esta consulta de agrupamento devolveria um resultado semelhante ao seguinte exemplo:

[
    {
        "numberOfDevices": 3,
        "status": "Success"
    },
    {
        "numberOfDevices": 2,
        "status": "Pending"
    },
    {
        "numberOfDevices": 1,
        "status": "Error"
    }
]

Neste exemplo, três dispositivos reportaram uma configuração bem-sucedida, dois ainda estão a aplicar a configuração e um reportou um erro.

As consultas de projeção permitem que os programadores devolvam apenas as propriedades que lhes interessam. Por exemplo, para recuperar o último tempo de atividade juntamente com o ID do dispositivo de todos os dispositivos ativados que estão desligados, use a seguinte consulta:

SELECT DeviceId, LastActivityTime FROM devices WHERE status = 'enabled' AND connectionState = 'Disconnected'

O resultado dessa consulta seria o seguinte exemplo:

[
  {
    "deviceId": "AZ3166Device",
    "lastActivityTime": "2021-05-07T00:50:38.0543092Z"
  }
]

Consultas de gêmeos de módulos

Consultar sobre gémeos de módulos é semelhante a consultar sobre gémeos de dispositivo, mas usando uma coleção/namespace diferente; em vez de devices, consulta-se a partir de devices.modules:

SELECT * FROM devices.modules

Não permitimos a junção entre as coleções de dispositivos e dispositivos.modules. Se quiseres consultar módulos gémeos entre dispositivos, faz-no com base nas tags. A consulta seguinte devolve todos os módulos gémeos em todos os dispositivos com o estado de varrimento:

SELECT * FROM devices.modules WHERE properties.reported.status = 'scanning'

A consulta seguinte devolve todos os gémeos de módulos com o estado de varredura, mas apenas no subconjunto especificado de dispositivos:

SELECT * FROM devices.modules
  WHERE properties.reported.status = 'scanning'
  AND deviceId IN ['device1', 'device2']

Limitações das consultas gémeas

Importante

Os resultados das consultas são operações eventualmente consistentes, e devem ser tolerados atrasos de até 30 minutos. Na maioria dos casos, a consulta gémea devolve resultados na ordem de alguns segundos. O Hub IoT se esforça para fornecer baixa latência para todas as operações. No entanto, devido às condições da rede e outros fatores imprevisíveis, não pode garantir uma certa latência.

Uma opção alternativa às consultas de gémeos é consultar gémeos de dispositivo individuais por ID usando a API get twin REST. A API devolve sempre os dados mais atuais e tem limites de utilização mais elevados. Pode emitir a API REST diretamente ou usar a funcionalidade equivalente num dos SDKs de Serviço Hub IoT do Azure.

As expressões de consulta podem ter um comprimento máximo de 8.192 caracteres.

Atualmente, as comparações são suportadas apenas entre tipos primitivos (sem objetos), por exemplo ... WHERE properties.desired.config = properties.reported.config , são suportadas apenas se essas propriedades tiverem valores primitivos.

Recomendamos não assumir uma dependência do lastActivityTime, encontrado nas Propriedades de Identidade do Dispositivo para consultas com o Twin em qualquer cenário. Este campo não garante uma medição precisa do estado do dispositivo. Em vez disso, utilize eventos do Ciclo de Vida do Dispositivo IoT para gerir o estado e as atividades do dispositivo. Para informações sobre como usar eventos do ciclo de vida do Hub IoT na sua solução, veja Reagir a eventos do Hub IoT usando o Event Grid para desencadear ações.

Nota

Evite fazer suposições sobre a latência máxima desta operação. Consulte Soluções de Latência para mais informações sobre como construir a sua solução tendo a latência em consideração.

Consultas para tarefas em Hub IoT

Os trabalhos fornecem uma forma de executar operações em conjuntos de dispositivos. Cada dispositivo gémeo contém a informação das tarefas que lhe são destinadas numa coleção chamada jobs. O Hub IoT permite-lhe consultar trabalhos como um único documento JSON contendo toda a informação dos gémeos.

Aqui está um exemplo de dispositivo gémeo hub IoT que faz parte de um trabalho chamado myJobId:

{
    "deviceId": "myDeviceId",
    "etag": "AAAAAAAAAAc=",
    "tags": {
        ...
    },
    "properties": {
        ...
    },
    "jobs": [
        {
            "deviceId": "myDeviceId",
            "jobId": "myJobId",
            "jobType": "scheduleUpdateTwin",
            "status": "completed",
            "startTimeUtc": "2016-09-29T18:18:52.7418462",
            "endTimeUtc": "2016-09-29T18:20:52.7418462",
            "createdDateTimeUtc": "2016-09-29T18:18:56.7787107Z",
            "lastUpdatedDateTimeUtc": "2016-09-29T18:18:56.8894408Z",
            "outcome": {
                "deviceMethodResponse": null
            }
        },
        ...
    ]
}

Atualmente, esta coleção pode ser consultada como devices.jobs na linguagem de consulta Hub IoT.

Importante

Atualmente, a propriedade jobs não é devolvida ao consultar dispositivos gémeos. Ou seja, consultas que contêm FROM devices. A propriedade jobs só pode ser acedida diretamente com consultas usando FROM devices.jobs.

Por exemplo, a consulta seguinte devolve todos os trabalhos (passados e agendados) que afetam um único dispositivo:

SELECT * FROM devices.jobs
  WHERE devices.jobs.deviceId = 'myDeviceId'

Note como esta consulta fornece o estado específico do dispositivo (e possivelmente a resposta direta do método) para cada tarefa devolvida.

Também é possível aplicar filtros usando condições booleanas arbitrárias em todas as propriedades dos objetos na coleção devices.jobs.

Por exemplo, a consulta seguinte recupera todos os trabalhos de atualização de dispositivos gémeos concluídos que foram criados após setembro de 2016 para um dispositivo específico:

SELECT * FROM devices.jobs
  WHERE devices.jobs.deviceId = 'myDeviceId'
    AND devices.jobs.jobType = 'scheduleUpdateTwin'
    AND devices.jobs.status = 'completed'
    AND devices.jobs.createdTimeUtc > '2016-09-01'

Também pode obter os resultados por dispositivo de um único trabalho.

SELECT * FROM devices.jobs
  WHERE devices.jobs.jobId = 'myJobId'

Limitações de consultas de empregos

As expressões de consulta podem ter um comprimento máximo de 8.192 caracteres.

Atualmente, as consultas em devices.jobs não suportam:

  • Projeções, portanto, só SELECT * são possíveis.
  • Condições que se referem ao gémeo do dispositivo além das propriedades do trabalho (ver a secção anterior).
  • Agregações, como contagem, média e agrupar por.