Artikel-Nr.: JQ Expressions for Digital Twin Adapters

Praktische JQ-Ausdrucksmuster für Geräteeingänge, Adapterumschläge, Routenbedingungen und Payload-Mappings, um Telemetrie in das zu normalisieren, was in den digitalen Zwillingsmodellen definiert ist.

Schlüsselkonzepte

Sie können JQ-Ausdrücke in einem digitalen Zwillingsadapter als Platzhalter ${ ... } schreiben, um Zielwerte in payload-mapping zu berechnen und Routingbedingungen auszuwerten.

Allgemeine Möglichkeiten zur Verwendung von JQ-Ausdrücken:

  • Geräteeingabe: Von Geräten gepostete Raw-Payloads.
  • Envelope: Deklariert Referenzendpunkte und Beispiel-Payload-Ausprägungen. Beispiel: Sie können das timeObserved-Mapping definieren.
  • Routen: Bewerten Sie Bedingungen wie Endpunkte, Header, Body, und wählen Sie eine Payload-Zuordnung aus.
  • Payload-Zuordnungen: Transformieren, konvertieren Sie Einheiten, benennen Sie Schlüssel um, und normalisieren Sie sie in das DTDL-Modellschema.
  • Ausgabe: Die normalisierte JSON-Ausgabe, die der Validierung des digitalen Zwillingsmodells entsprechen muss, einschließlich Typen, Bereichen, Einheiten.
  • Unterstützung der Zuordnungsfunktion: Arithmetische und floor-Funktionen werden akzeptiert. Funktionen wie toInteger und number werden nicht unterstützt.
  • Endpunktabgleich: Verwendet segmentbasierte Bedingungen mit endpoint(n). Beispiel: ${endpoint(1) == 'home' and endpoint(2) == 'sonnen' and endpoint(3) == 'status'} anstelle nicht unterstützter Platzhaltermuster.
  • Ganzzahl vs. doppeltes Schema:
    • Stellen Sie für schema: "integer" sicher, dass das Mapping Integralzahlen ausgibt (Beispiel: "${(.velocity_kph / 1.609) | floor}").
    • Für schema: "double" werden fraktionierte Ausgaben akzeptiert. Verwenden Sie floor nur, wenn Sie ganzzahligen Speicher als doppelten Speicher verwenden möchten, z.B. 68.0.
  • Soft-Konvertierungstyp: Numerische Zeichenfolgen und Ganzzahlendoppelungen werden akzeptiert, wenn sie mit dem Modelltyp übereinstimmen (z.B. Ganzzahl). Casting-Helfer wie number() und toInteger werden in Routenausdrücken weiterhin nicht unterstützt. Verlassen Sie sich auf arithmetische Werte und floor, oder übernehmen Sie schema: "double", um Fraktionen beizubehalten.
    • Pass-Through (mph, Schema "integer"): {"speed": "60"} und {"speed": 60.0} werden als 60 gespeichert. {"speed": "60.2"} wird abgelehnt, es sei denn, Coerces werden einer Ganzzahl zugeordnet, z.B. mit floor.
    • Metrikroute (kph → mph): {"velocity_kph": 110}68; {"velocity_kph": "110"}68, da das Mapping floor eine Ganzzahl ausgibt. Behalten Sie arithmetische Eingaben numerisch bei, um Ausdrucksfehler zu vermeiden. Verwenden Sie nach Möglichkeit 110 gegenüber "110".
    • Rundung bleibt explizit: Bei der Soft-Konvertierung wird 68.35 nicht automatisch in 68 gerundet. Verwenden Sie floor als Ganzzahlenschema, oder wechseln Sie das Modell zu schema: "double", um Brüche beizubehalten.
  • Envelope- und Zeitverarbeitung: Wenn timeObserved nicht angegeben ist, kann die Plattform receivedTime verwenden. Verwenden Sie fromdateformat, todateformat und zugehörige Funktionen für Zeitkonvertierungen in Envelope- oder Payload-Zuordnungen.
Hinweis

Die Datenvalidierung erfolgt für Ihr DTDL-Modell. Wenn eine Eigenschaft als integer deklariert wird, muss die normalisierte Ausgabe ein integer-Wert und kein string oder float sein. Siehe das Ganzzahl-Fixierungsmuster unten.

Weitere Informationen finden Sie in der Referenz zu DTMI Validation Extension.

Beispiele für Geräteeingaben

Typische eingehende Payloads mit einheitsspezifischen Schemas:

Standard USA Einheiten Meilen pro Stunde:

{
  "speed": 60
}

Europäische metrische Einheiten Kilometer pro Stunde:

{
  "velocity_kph": 110
}

Verschachtelte Nutzlast von einem Sensor:

{
  "telemetry": { "temp_c": 22.4, "humidity": 48 }
}

Beispiele:

{
  "samples": [ { "kph": 30 }, { "kph": 50 }, { "kph": 0 } ]
}

Diese Beispiele zeigen ein DTDL-Modell, bei dem die Temperatur eine ganze Zahl zwischen 0 und 100 ist und die Feuchtigkeit optional ist.

Wenn beide Werte vorhanden sind und die Temperatur innerhalb des zulässigen Bereichs und des richtigen Typs liegt, ist sie gültig, und der vollständige Eingabewert wird aufgenommen:
{ "temperature": 60, "humidity": 45 }
Wenn ein Wert abwesend ist, werden nur die gültigen Daten aufgenommen. In diesem Beispiel fehlt die Temperatur, sodass die Feuchtigkeit aufgenommen und der Temperaturwert nicht aktualisiert wird.
{
"humidity": 45
}
Wenn ein Wert null ist, wird er ignoriert, und nur der gültige Wert wird aufgenommen:
{
		“temperature”: null
 		“humidity”: 45
	}

Envelope-Zuordnung

Die envelope.json deklariert eine referenceEndpoint und eine referencePayload. Optional kann eine Envelope-Zuordnung time-observed festlegen:

{
  "referenceEndpoint": "telemetry/automotive/standard",
  "referencePayload": {
    "dataFormat": "JSON",
    "data": { "speed": 65 }
  }
}
Hinweis

Die spezielle ID receivedTime kann von der Plattform bereitgestellt werden, wenn das Gerät time auslässt. Wenn die Envelope-Zuordnung angegeben ist und einen Wert von timeObserved enthält, wird receivedTime als Wert von timeObserved verwendet.

Routenbedingungsmuster

Routingbedingungen sind Regeln oder Ausdrücke, mit denen bestimmt wird, welche Mapping- oder Verarbeitungsregel auf eine eingehende Nachricht oder Anforderung angewendet werden soll. Wenn die Auswertung einer Routingbedingung "true" ergibt, wird die zugehörige Mapping- oder Transformationsregel ausgelöst und angewendet.

In diesem Beispiel definiert die Routingbedingung des digitalen Zwillingsadapters zwei Routen zur Verarbeitung eingehender Gerätenachrichten, basierend auf dem Format der Daten. Beispiel: Wenn Metrikeinheiten im 3. Segment des Endpunktpfads empfangen werden, /vehicle/speed/metric-units/, dann

[
  {
    "description": "European metric to mph; convert then floor (no explicit cast).",
    "condition": "${endpoint(3) == \"metric-units\"}",
    "payloadMapping": {
      "$.speed": "${(.velocity_kph / 1.609) | floor}"
    },
    "referencePayload": {
      "dataFormat": "JSON",
      "data": { "velocity_kph": 104 }
    }
  },
  {
    "description": "USA standard units passthrough.",
    "condition": "*",
    "payloadMapping": { "$.speed": "$.speed" }
  }
]
  • endpoint(n) wählt das n-th-Pfadsegment aus (je nach Adapter 0- oder 1-basiert). Im Normalisierungsszenario für Maßeinheiten wird endpoint(3) verwendet, sodass /vehicle/speed/metric-units/ mit dem dritten Segment metric-units übereinstimmt.
  • Platzieren Sie spezifischere Bedingungen vor dem Catch-All "*".
  • payloadMapping:
    • Nimmt die Geschwindigkeit im Feld velocity_kph in Kilometern pro Stunde von der Payload und konvertiert sie in Meilen pro Stunde: .velocity_kph / 1.609
    • Wendet floor an, um auf die nächste Ganzzahl abzurunden. floor wird nicht konvertiert. Daher kann das Ergebnis eine Gleitkommazahl sein.
    • Das Ergebnis wird dem Ausgabefeld speed zugewiesen.
  • referencePayload:
    • Zeigt die erwartete Eingabe für diese Route an: {"velocity_kph": 104}
  • Eingabeendpunkt: /vehicle/speed/metric-units/device123
  • Eingabe-Payload: { "velocity_kph": 104 } Ausgabezuordnung: { "speed": 64 } (since 104 / 1.609 = 64.64, floor is 64)

Payload-Zuordnungsbeispiele

Allgemeine JQ-Ausdrücke für Payload-Zuordnungen:

  • Weiterleitung: "$.speed": "$.speed"
  • Umbenennungsschlüssel: "$.speed": "${.velocity_kph}"
  • Einheitenkonvertierung: "$.mph": "${.kph / 1.609}"
  • Boden/Decke/Runde: "${.x | floor}", "${.x | ceil}", "${.x | round}"
  • Coalesce/Standard (versionabhängig): "${ if .value? then .value else 0 end }"
  • Typkonvertierung:
    • Bis Nummerierung: "${.value | tonumber}" (unterstützt tonumber in den meisten Builds)
    • Bis Zeichenfolge: "${.value | tostring}"
    Hinweis

    In einem IoT Digital Twin Adapter werden Casting-Funktionen wie toInteger oder number in inbound-routes nicht akzeptiert. Sie können arithmetische Werte verwenden, bei denen floor für ein Ganzzahlenschema definiert ist, oder schema: "double" und Rundungsformate für die Downstream-Datenaufnahme verwenden. inbound-routes muss ein gültiges JSON sein. Ausdrücke gehören zu den in Anführungszeichen gesetzten Zeichenfolgen "${ ... }".
  • Schachtelte Extraktion: "${.telemetry.temp_c}"
  • Arrayzuordnung: "${[ .samples[] | .kph / 1.609 | floor ]}"
  • Bedingung: "${ if .kph > 0 then .kph / 1.609 else 0 end }"
Hinweis

Je nach Adapterintegration können Ausdrücke in Anführungszeichen "${...}" als Zeichenfolgen serialisiert werden. Wenn die Engine nicht in Anführungszeichen stehende Ausdrücke unterstützt, z.B. ${...} als RAW-Wert, wird empfohlen, dass dieses Formular eine JSON-Nummer anstelle einer Zeichenfolge ausgibt.

Nuancen: Ganzzahlen, Zeichenfolgen und berechnete Zahlen

Wenn eine DTDL-Eigenschaft schema: "integer" ist, muss die normalisierte Ausgabe ein Ganzzahltyp sein. Zwei allgemeine Fehlermodi beim Berechnen von Werten:

  1. Zeichenfolge: Ein Ausdruck, der in Anführungszeichen eingeschlossen ist, kann "68" (Zeichenfolge) ergeben, wobei die Ganzzahlvalidierung nicht erfolgreich war.
  2. Variable Zahlen: Arithmetisch erzeugt 68.0. Einige Validatoren behandeln diese Zahlen auch dann als nicht ganzzahlig, wenn sie mathematisch integriert sind.

Muster korrigieren:

  • Nur Floor verwenden für Ganzzahlenschema: "${(.velocity_kph / 1.609) | floor}", um eine ganzzahlige Zahl zu erstellen, die Ganzzahltyping erfüllt.
  • Alternativ: Wechseln Sie die Modelleigenschaft zu schema: "double", um die Nachkommastellen für Bruchteile beizubehalten, oder wenden Sie floor in der Zuordnung an, während Sie eine ganze Zahl als Double speichern. Runden/Formatieren in APEX/SQL nach Bedarf.

Beispiele für Digital Twin Adapter Mapping

In diesem Beispiel werden Kilometer pro Stunde (KPH) in Meilen pro Stunde (MPH) mit floor (kein Cast) normalisiert.

{
  "description": "European auto uses metric units; convert to mph and floor to whole number.",
  "condition": "${endpoint(3) == \"metric-units\"}",
  "payloadMapping": {
    "$.speed": "${(.velocity_kph / 1.609) | floor}"
  },
  "referencePayload": {
    "dataFormat": "JSON",
    "data": { "velocity_kph": 104 }
  }
}

Beispiel: Standard-Catch-All-Passthrough

{
  "description": "English units passthrough.",
  "condition": "*",
  "payloadMapping": {
    "$.speed": "$.speed"
  }
}

Beispiel: Verschachtelter Telemetrie- und Koaleszenzstandard

{
  "description": "Extract nested temp; default to 0 when missing.",
  "condition": "${endpoint(2) == \"env\"}",
  "payload-mapping": {
    "$.room_temp_c": "${ if .telemetry.temp_c? then .telemetry.temp_c else 0 end }"
  }
}

Beispiel: Array-Normalisierung

{
  "description": "Normalize kph samples to mph (whole-number mph via floor).",
  "condition": "${.samples?}",
  "payload-mapping": {
    "$.speeds": "${ [ .samples[] | .kph / 1.609 | floor ] }"
  }
}

Ausgabeerwartungen vs. Modellvalidierung

Ausgänge müssen den Schemata und Einschränkungen des digitalen Zwillingsmodells entsprechen. Informationen zum Modell von Automobilen in model.json finden Sie unter Szenario: Maßeinheiten mit einem digitalen Zwillingsadapter normalisieren:

  • name: speed
  • schema: integer
  • unit: milePerHour
  • minimum: 0, maximum: 100

Normalisierte speed muss eine Ganzzahl innerhalb von 0,100 sein. Die Validierung einer berechneten Zeichenfolge "68" oder Gleitkommazahl 68.0 ist nicht erfolgreich.

Einschränkungen und Tipps

  • Filterverfügbarkeit variiert: Die meisten Core-JQ-Filter (floor, ceil, round, tonumber, tostring, map, select, add)
  • Emission eingeben: Ausdrücke, die in Zeichenfolgen in Anführungszeichen eingebettet sind, können als Zeichenfolgen serialisiert werden. Verwenden Sie Raw-Ausdrücke ohne Anführungszeichen, wenn numerische Typen ausgegeben werden sollen.
  • Nullbehandlung: Bei Vorgängen auf null kann null erzeugt werden. Verwenden Sie if .x? then ... else ... end für defensive Standardwerte.
  • Präzision: Gleitkommaarithmetik kann Rundungsartefakte einführen. Wenden Sie round und floor nach Bedarf vor dem Casting an.
  • Ganzzahl-Cast: In beobachteten Tests wurden toInteger und number bei der Adaptererstellung in inbound-routes nicht akzeptiert. Bevorzugt arithmetisch + floor für Ganzzahlenschema, oder verwenden Sie schema: "double", und runden Sie das Format nachgelagert.

Ganzzahlkorrektur auf das Automobilszenario anwenden

Das Szenario erstellt ein Modell mit einer Ganzzahl speed und leitet die Payloads der Metrikeinheiten an dasselbe digitale Zwillingsmodell weiter. Ohne expliziten Cast kann der berechnete Wert durch Validierung aufgrund von Typ Drift (String oder Float-like Number) abgelehnt werden.

Im Szenario verwendete Fix:

"$.speed": "${(.velocity_kph / 1.609) | floor}"

Warum dies erforderlich ist:

  • floor stellt sicher, dass der Wert ganzzahlig ist und die Eingabe von Ganzzahl erfüllt.
  • Alternative: Verwenden Sie schema: "double", um die Bruchstellengenauigkeit beizubehalten und bei Bedarf nachgelagert zu runden und zu formatieren.
Hinweis

Wenn Sie ein Ganzzahlenschema verwenden, bevorzugen Sie Arithmetik plus floor. Bei einem doppelten Schema können Sie floor weglassen, um die partielle MPH beizubehalten, oder es einschließen, um eine ganze Zahl MPH als doppelten Wert zu speichern.

Schnellreferenz-Snippets

Unterstützte Beispiele:

  • Bedingung: Endpunktübereinstimmung: "condition": "${endpoint(3) == \"metric-units\"}"
  • Zuordnung: Durchgang: "$.speed": "$.speed"
  • Zuordnung: kph → mph (Ganzzahlschema): "$.speed": "${(.kph / 1.609) | floor}"
  • Zuordnung: Verschachtelt: "$.room_temp_c": "${.telemetry.temp_c}"
  • Zuordnung: Standard: "$.value": "${ if .value? then .value else 0 end }"
  • Arraytransformation: "$.list": "${ [ .arr[] | .x | tonumber ] }"

Verhalten von Ganzzahl- und Doppelmodell

In diesem Abschnitt wird zusammengefasst, wie sich der Modellschematyp auf die Adapterzuordnung und -validierung auswirkt.

  • Schema: "integer"
    • Typ: Muss eine Ganzzahl-JSON-Nummer sein, die integral ist. Zeichenfolgen wie 68 oder Float-ähnliche Ergebnisse 68.0 können die Ganzzahlvalidierung nicht erfolgreich verlaufen.
    • Zuordnung: Arithmetik ist zulässig. floor wird unterstützt. Funktionen wie toInteger und number werden nicht unterstützt.
    • Muster: Verwenden Sie "${(.velocity_kph / 1.609) | floor}", um MPH zu integrieren. Dies hat die Validierung bestanden und die Telemetrie wurde HTTP 202 akzeptiert.
    • Bereich: Mindest- und Höchstwerte werden durchgesetzt. Beispiel: 0–100
  • schema: "double"
    • Typ: Alle Integral- oder Bruchteile von JSON-Nummern werden akzeptiert, wenn sie innerhalb des Bereichs liegen. Die Plattform führt keine automatische Rundung durch.
    • Zuordnung: Sie können die Anzahl der Nachkommastellen beibehalten, z.B. "${.velocity_kph / 1.609}", oder auch floor anwenden, um eine Ganzzahl-MPH zu erzeugen, die als Double gespeichert ist. Beispiel: 68.0
    • Bereich: Wenn definiert, werden Minimum und Maximum durchgesetzt. Beispiel: 0–100

Beobachtete Telemetrieergebnisse

Die folgenden Kombinationen wurden End-to-End validiert (HTTP/1.1 202 Accepted):

  • Ganzzahlenmodell + Bodenzuordnung: "${(.velocity_kph / 1.609) | floor}" → akzeptiert
  • Doppeltes Modell + Raw-Zuordnung: "${.velocity_kph / 1.609}" → Bruchteilige php akzeptiert
  • Doppelmodell + Bodenzuordnung: "${(.velocity_kph / 1.609) | floor}" → ganze Zahlen-Phase akzeptiert und als doppelt gespeichert

Beispiel für curl (Platzhalter)

Doppeltes Modell, Rohwert, der wie erwartet fraktionierte MPH ist:

curl -i -X POST \
  -u "european-auto-raw:secret-or-certificate-ocid" \
  -H "Content-Type: application/json" \
  "https://device-host/telemetry/automotive/metric-units" \
  -d '{ "velocity_kph": 110 }'

Doppeltes Modell, Boden eine ganze Zahl MPH, das als doppelt gespeichert ist:

curl -i -X POST \
  -u "european-auto-dfloor:secret-or-certificate-ocid" \
  -H "Content-Type: application/json" \
  "https://device-host/telemetry/automotive/metric-units" \
  -d '{ "velocity_kph": 110 }'

Erwartete HTTP-Antwort für jeden Fall:

HTTP/1.1 202 Accepted
content-type: text/plain

Accepted

Überlegungen zu Downstream in APEX oder SQL

  • Bei double wird die Bruchzahl beibehalten. Verwenden Sie SQL FLOOR/ROUND für die Anzeige ganzer Zahlen:
    SELECT FLOOR(speed) AS speed_mph FROM ...
  • Stellen Sie mit integer sicher, dass die Zuordnung Integralwerte ausgibt (z.B. über floor), um die Validierung zu erfüllen.

Autorisierungsbenutzername und -angebote

In OCI IoT entspricht die Verwendung des Basisauthentifizierungsbenutzernamens der Instanz external-key. Wenn die Instanz mit eingebetteten Anführungszeichen im externen Schlüssel erstellt wird, werden diese Anführungszeichen Teil des erforderlichen Benutzernamens und müssen wörtlich gesendet werden. Dies führt häufig zu Problemen bei der Angebotserstellung.

Best Practice: Erstellen Sie digitale Zwillingsinstanzen mit externen Schlüsseln, die keine Anführungszeichen enthalten. Beispiel: american-auto Wenn Sie sich mit Benutzernamen in Anführungszeichen authentifizieren müssen, erstellen Sie einen Authorization: Basic ...-Header, anstatt -u zu verwenden, um Fehler bei der Angebotserstellung zu vermeiden.