IoT Hub-querytaal voor apparaat- en moduledubbels, taken en-berichtroutering

IoT Hub biedt een krachtige SQL-achtige taal voor het ophalen van informatie over apparaat-tweelingen, module-tweelingen, takenen berichtroutering. In dit artikel wordt het volgende beschreven:

  • Een inleiding tot de belangrijkste functies van de IoT Hub querytaal, en
  • De gedetailleerde beschrijving van de taal. Zie Query's in berichtroutering voor meer informatie over querytaal voor berichtroutering.

Notitie

Sommige van de functies die in dit artikel worden genoemd, zoals cloud-naar-apparaat-berichten, apparaatdubbels en apparaatbeheer, zijn alleen beschikbaar in de standaardlaag van IoT Hub. Raadpleeg How to choose the right IoT Hub tier (De juiste IoT Hub-prijscategorie kiezen) voor meer informatie over de Basic- en Standard-prijscategorieën van IoT Hub.

Query's voor apparaat- en module dubbels

Apparaat-tweelingen en module-tweelingen kunnen willekeurige JSON-objecten bevatten als tags en eigenschappen. IoT Hub kunt u een query uitvoeren op apparaat-tweelingen en module-tweelingen als één JSON-document met alle dubbele gegevens.

Stel dat uw IoT Hub-apparaattweeling de volgende structuur heeft (module dubbel is vergelijkbaar met alleen een extra 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
        }
    }
}

Query's voor apparaattwee

IoT Hub de apparaattweeling beschikbaar als een documentverzameling met de naam apparaten. Met de volgende query wordt bijvoorbeeld de hele set apparaattweelingen opgehaald:

SELECT * FROM devices

Notitie

Azure IoT SDK's bieden ondersteuning voor het pagineren van grote resultaten.

IoT Hub kunt u het filteren van apparaattweeling met willekeurige voorwaarden ophalen. Als u bijvoorbeeld apparaattweelingen wilt ontvangen waarbij de tag location.region is ingesteld op US, gebruikt u de volgende query:

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

Booleaanse operators en rekenkundige vergelijkingen worden ook ondersteund. Als u bijvoorbeeld apparaattweelingen in de VERENIGDE Staten wilt ophalen en zo wilt configureren dat telemetrie minder dan elke minuut wordt verzenden, gebruikt u de volgende query:

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

Voor het gemak is het ook mogelijk om matrixconstanten te gebruiken met de operators IN en NIN (niet in). Als u bijvoorbeeld apparaattweeling wilt ophalen die Wi-Fi- of bekabelde connectiviteit rapporteren, gebruikt u de volgende query:

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

Het is vaak nodig om alle apparaattweelingen te identificeren die een specifieke eigenschap bevatten. IoT Hub ondersteunt de functie is_defined() voor dit doel. Als u bijvoorbeeld apparaattweelingen wilt ophalen die de eigenschap connectivity definiëren, gebruikt u de volgende query:

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

Raadpleeg de sectie WHERE-component voor een volledig overzicht van de filtermogelijkheden.

Groepering en aggregaties worden ook ondersteund. Als u bijvoorbeeld het aantal apparaten in elke telemetrieconfiguratiestatus wilt vinden, gebruikt u de volgende query:

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

Deze groeperingsquery retourneert een resultaat dat lijkt op het volgende voorbeeld:

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

In dit voorbeeld hebben drie apparaten een geslaagde configuratie gerapporteerd, twee passen de configuratie nog steeds toe en één heeft een fout gerapporteerd.

Met projectiequery's kunnen ontwikkelaars alleen de eigenschappen retourneren die ze belangrijk vinden. Als u bijvoorbeeld de laatste activiteitstijd wilt ophalen, samen met de apparaat-id van alle ingeschakelde apparaten die zijn losgekoppeld, gebruikt u de volgende query:

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

Hier is een voorbeeld van een queryresultaat van die query in Query Explorer voor een IoT Hub:

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

Query's voor module twin

Het uitvoeren van query's op module-tweelingen is vergelijkbaar met het uitvoeren van query's op apparaattweelingen, maar met behulp van een andere verzameling/naamruimte; in plaats van vanaf apparaten, kunt u een query uitvoeren vanuit devices.modules:

SELECT * FROM devices.modules

Er is geen join tussen de verzamelingen devices en devices.modules toegestaan. Als u query's wilt uitvoeren op module-tweelingen op meerdere apparaten, doet u dit op basis van tags. Met deze query worden alle module-tweelingen op alle apparaten met de scanstatus retourneren:

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

Deze query retourneert alle module-tweelingen met de scanstatus, maar alleen op de opgegeven subset van apparaten:

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

C#-voorbeeld

De queryfunctionaliteit wordt beschikbaar gemaakt door de C#-service-SDK in de klasse RegistryManager.

Hier is een voorbeeld van een eenvoudige query:

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

Het queryobject wordt gemaakt met een paginaformaat (maximaal 100). Vervolgens worden meerdere pagina's opgehaald door de GetNextAsTwinAsync-methoden meerdere keren aan te roepen.

Het queryobject maakt meerdere Volgende-waarden beschikbaar, afhankelijk van de deserialisatieoptie die is vereist voor de query. Bijvoorbeeld apparaat-dubbel- of taakobjecten, of gewone JSON bij het gebruik van projecties.

Node.js voorbeeld

De queryfunctionaliteit wordt beschikbaar gemaakt door de Azure IoT-service-SDK voor Node.jsin het registerobject.

Hier is een voorbeeld van een eenvoudige query:

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);

Het queryobject wordt gemaakt met een paginaformaat (maximaal 100). Vervolgens worden meerdere pagina's opgehaald door de methode nextAsTwin meerdere keren aan te roepen.

Het queryobject maakt meerdere Volgende-waarden beschikbaar, afhankelijk van de deserialisatieoptie die is vereist voor de query. Bijvoorbeeld apparaat-dubbel- of taakobjecten, of gewone JSON bij het gebruik van projecties.

Beperkingen

Belangrijk

Queryresultaten kunnen enkele minuten vertraging hebben met betrekking tot de meest recente waarden in apparaattweelingen. Als u query's uitvoert op afzonderlijke apparaat tweelingen op id, gebruikt u de get twin REST API. Deze API retourneert altijd de meest recente waarden en heeft hogere beperkingslimieten. U kunt de REST API rechtstreeks uitgeven of de equivalente functionaliteit gebruiken in een van de Azure IoT Hub Service SDK's.

Op dit moment worden vergelijkingen alleen ondersteund tussen primitieve typen (geen objecten), bijvoorbeeld alleen ondersteund als deze eigenschappen ... WHERE properties.desired.config = properties.reported.config primitieve waarden hebben.

Aan de slag met takenquery's

Taken bieden een manier om bewerkingen uit te voeren op sets apparaten. Elke apparaat dubbel bevat de informatie van de taken waarvan deze deel uitmaakt in een verzameling met de naam jobs.

{
    "deviceId": "myDeviceId",
    "etag": "AAAAAAAAAAc=",
    "tags": {
        ...
    },
    "properties": {
        ...
    },
    "jobs": [
        {
            "deviceId": "myDeviceId",
            "jobId": "myJobId",
            "jobType": "scheduleTwinUpdate",
            "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
            }
        },
        ...
    ]
}

Deze verzameling kan momenteel worden opgevraagd als devices.jobs in de IoT Hub querytaal.

Belangrijk

Op dit moment wordt de eigenschap jobs nooit geretourneerd bij het uitvoeren van query's op apparaattweelingen. Dat wil zeggen, query's die 'FROM-apparaten' bevatten. De eigenschap jobs kan alleen rechtstreeks worden gebruikt met query's met behulp van FROM devices.jobs .

Als u bijvoorbeeld alle taken (afgelopen en gepland) wilt opvragen die van invloed zijn op één apparaat, kunt u de volgende query gebruiken:

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

Houd er rekening mee dat deze query de apparaatspecifieke status (en mogelijk het antwoord van de directe methode) van elke geretourneerde taak biedt.

Het is ook mogelijk om te filteren met willekeurige Booleaanse voorwaarden op alle objecteigenschappen in de devices.jobs verzameling.

Als u bijvoorbeeld alle voltooide updatetaken voor apparaattweeling wilt ophalen die na september 2016 zijn gemaakt voor een specifiek apparaat, gebruikt u de volgende query:

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

U kunt ook de resultaten per apparaat van één taak ophalen.

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

Beperkingen

Op dit moment bieden query'devices.jobs geen ondersteuning voor:

  • Projecties zijn daarom SELECT * alleen mogelijk.
  • Voorwaarden die naast taakeigenschappen naar de apparaat dubbel verwijzen (zie de vorige sectie).
  • Aggregaties uitvoeren, zoals aantal, gemiddelde, groeperen op.

Basisbeginselen van IoT Hub query

Elke IoT Hub query bestaat uit SELECT- en FROM-component, met optionele WHERE- en GROUP BY-component. Elke query wordt uitgevoerd op een verzameling JSON-documenten, bijvoorbeeld apparaattweelingen. De COMPONENT FROM geeft aan dat de documentverzameling moet worden geïn itereerd op (apparaten, devices.modules of devices.jobs). Vervolgens wordt het filter in de WHERE-component toegepast. Met aggregaties worden de resultaten van deze stap gegroepeerd zoals opgegeven in de GROUP BY-component. Voor elke groep wordt een rij gegenereerd zoals opgegeven in de SELECT-component.

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

FROM-component

De FROM <from_specification>-component kan slechts drie waarden aannemen: FROM devices to query device twins, FROM devices.modules to query module twins of FROM devices.jobs to query job per device details.

WHERE-component

De where<filter_condition> component is optioneel. Hiermee geeft u een of meer voorwaarden op waar de JSON-documenten in de from-verzameling aan moeten voldoen om te worden opgenomen als onderdeel van het resultaat. Elk JSON-document moet de opgegeven voorwaarden evalueren naar 'true' om in het resultaat te worden opgenomen.

De toegestane voorwaarden worden beschreven in de sectie Expressies en voorwaarden.

SELECT-component

De SELECT<select_list> is verplicht en geeft aan welke waarden worden opgehaald uit de query. Hiermee geeft u de JSON-waarden op die moeten worden gebruikt voor het genereren van nieuwe JSON-objecten. Voor elk element van de gefilterde (en optioneel gegroepeerde) subset van de verzameling FROM genereert de projectiefase een nieuw JSON-object. Dit object wordt samengesteld met de waarden die zijn opgegeven in de SELECT-component.

Hieronder volgt de grammatica van de SELECT-component:

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 verwijst naar een eigenschap van het JSON-document in de verzameling FROM. Enkele voorbeelden van SELECT-component vindt u in de sectie Aan de slag met query's voor apparaattwee.

Op dit moment worden selectieclausules die verschillen van SELECT* alleen ondersteund in statistische query's op apparaattweelingen.

Clausule GROUP BY

De GROUP BY <group_specification>-component is een optionele stap die wordt uitgevoerd na het filter dat is opgegeven in de WHERE-component en vóór de projectie die is opgegeven in select. Het groepeert documenten op basis van de waarde van een kenmerk. Deze groepen worden gebruikt voor het genereren van geaggregeerde waarden zoals opgegeven in de SELECT-component.

Een voorbeeld van een query met GROUP BY is:

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

De formele syntaxis voor GROUP BY is:

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

Attribute_name verwijst naar een eigenschap van het JSON-document in de verzameling FROM.

Op dit moment wordt de GROUP BY-component alleen ondersteund bij het uitvoeren van query's op apparaattweelingen.

Belangrijk

De term group wordt momenteel behandeld als een speciaal trefwoord in query's. Als u gebruikt als de naam van uw eigenschap, kunt u overwegen deze om te sluiten met dubbele haken om fouten group te voorkomen, bijvoorbeeld SELECT * FROM devices WHERE tags.[[group]].name = 'some_value' .

Expressies en voorwaarden

Op hoog niveau een expressie:

  • Evalueert naar een exemplaar van een JSON-type (zoals Booleaanse tekst, getal, tekenreeks, matrix of object).
  • Wordt gedefinieerd door gegevens te bewerken die afkomstig zijn van het JSON-document en constanten van het apparaat met behulp van ingebouwde operators en functies.

Voorwaarden zijn expressies die worden geëvalueerd als een Booleaanse booleaanse. Elke constante die anders is dan Booleaanse true wordt als onwaar beschouwd. Deze regel bevat null, niet-gedefinieerd, elk object of matrix-exemplaar, een tekenreeks en de Booleaanse waarde false.

De syntaxis voor expressies is:

<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>]+ ']'

Raadpleeg de volgende tabel om te begrijpen waar elk symbool in de expressiesyntaxis voor staat:

Symbool Definitie
attribute_name Elke eigenschap van het JSON-document in de from-verzameling.
binary_operator Elke binaire operator die wordt vermeld in de sectie Operators.
function_name Een functie die wordt vermeld in de sectie Functies.
decimal_literal Een float uitgedrukt in decimale notatie.
hexadecimal_literal Een getal dat wordt uitgedrukt door de tekenreeks '0x' gevolgd door een tekenreeks van hexadecimale cijfers.
string_literal Letterlijke tekenreeksen zijn Unicode-tekenreeksen die worden vertegenwoordigd door een reeks van nul of meer Unicode-tekens of escape-reeksen. Letterlijke tekenreeksen worden tussen enkele aanhalingstekens of dubbele aanhalingstekens ingesloten. Toegestane escapes: \' , , , voor \" \\ \uXXXX Unicode-tekens die zijn gedefinieerd door 4 hexadecimale cijfers.

Operators

De volgende operators worden ondersteund:

Familie Operators
Rekenkundig +, -, *, /, %
Logisch EN, OF, NIET
Vergelijking =, !=, <, >, <=, >=, <>

Functions

Bij het uitvoeren van query's op tweelingen en taken is de enige ondersteunde functie:

Functie Beschrijving
IS_DEFINED(eigenschap) Retourneert een Booleaanse waarde die aangeeft of aan de eigenschap een waarde is toegewezen (inclusief null ).

In routes worden de volgende wiskundige functies ondersteund:

Functie Beschrijving
ABS(x) Retourneert de absolute (positieve) waarde van de opgegeven numerieke expressie.
EXP(x) Retourneert de exponentiële waarde van de opgegeven numerieke expressie (e^x).
POWER(x,y) Retourneert de waarde van de opgegeven expressie naar de opgegeven macht (x^y).
SQUARE(x) Retourneert het kwadraat van de opgegeven numerieke waarde.
CEILING(x) Retourneert het kleinste gehele getal dat groter is dan of gelijk is aan de opgegeven numerieke expressie.
FLOOR(x) Retourneert het grootste gehele getal dat kleiner is dan of gelijk is aan de opgegeven numerieke expressie.
SIGN(x) Retourneert het positieve (+1), nul (0) of negatieve (-1) teken van de opgegeven numerieke expressie.
SQRT(x) Retourneert de vierkantswortel van de opgegeven numerieke waarde.

In routes worden de volgende typecontrole- en cast-functies ondersteund:

Functie Beschrijving
AS_NUMBER Converteert de invoerreeks naar een getal. noop als invoer een getal is; Undefined als tekenreeks geen getal vertegenwoordigt.
IS_ARRAY Retourneert een Booleaanse waarde die aangeeft of het type van de opgegeven expressie een matrix is.
IS_BOOL Retourneert een Booleaanse waarde die aangeeft of het type van de opgegeven expressie een Booleaanse waarde is.
IS_DEFINED Retourneert een Booleaanse waarde die aangeeft of aan de eigenschap een waarde is toegewezen. Dit wordt alleen ondersteund als de waarde een primitief type is. Primitieve typen zijn tekenreeks, Booleaanse waarde, numeriek of null . DateTime, objecttypen en matrices worden niet ondersteund.
IS_NULL Retourneert een Booleaanse waarde die aangeeft of het type van de opgegeven expressie null is.
IS_NUMBER Retourneert een Booleaanse waarde die aangeeft of het type van de opgegeven expressie een getal is.
IS_OBJECT Retourneert een Booleaanse waarde die aangeeft of het type van de opgegeven expressie een JSON-object is.
IS_PRIMITIVE Retourneert een Booleaanse waarde die aangeeft of het type van de opgegeven expressie een primitieve is (tekenreeks, Booleaanse waarde, numeriek of null ).
IS_STRING Retourneert een Booleaanse waarde die aangeeft of het type van de opgegeven expressie een tekenreeks is.

In routes worden de volgende tekenreeksfuncties ondersteund:

Functie Beschrijving
CONCAT(x, y, ...) Retourneert een tekenreeks die het resultaat is van het samenvoegen van twee of meer tekenreekswaarden.
LENGTH(x) Retourneert het aantal tekens van de opgegeven tekenreeksexpressie.
LOWER(x) Retourneert een tekenreeksexpressie na het converteren van tekens in hoofdletters naar kleine letters.
UPPER(x) Retourneert een tekenreeksexpressie na het converteren van tekens in kleine letters naar hoofdletters.
SUBSTRING(string, start [, length]) Retourneert een deel van een tekenreeksexpressie beginnend bij de opgegeven tekenpositie op basis van nul en gaat door met de opgegeven lengte of aan het einde van de tekenreeks.
INDEX_OF(tekenreeks, fragment) Retourneert de beginpositie van het eerste exemplaar van de tweede tekenreeksexpressie binnen de eerste opgegeven tekenreeksexpressie, of -1 als de tekenreeks niet is gevonden.
STARTS_WITH(x, y) Retourneert een Booleaanse tekst die aangeeft of de eerste tekenreeksexpressie begint met de tweede.
ENDS_WITH(x, y) Retourneert een Booleaanse tekst die aangeeft of de eerste tekenreeksexpressie eindigt met de tweede.
CONTAINS(x,y) Retourneert een Booleaanse waarde die aangeeft of de eerste tekenreeksexpressie de tweede bevat.

Volgende stappen

Meer informatie over het uitvoeren van query's in uw apps met behulp van Azure IoT SDK's.