JSON Query - Teil 2

  Ralf Hersel   Lesezeit: 5 Minuten  🗪 1 Kommentar

Wie filtert man mit dem Werkzeug jq und stellt mehrere Werte in einer Zeile dar? Ein Artikel aus dem beruflichen Alltag.

json query - teil 2

Es gibt bei GNU/Linux.ch Serien, die sich über mehrere Jahre hinziehen. Den ersten Artikel über JSON Query habe ich im März 2021 geschrieben. Heute wollte ich aus einem Trello-KanBan-Board die Karten-Titel einer bestimmten Liste exportieren. Ohne etwas dafür zu bezahlen, bietet Trello nur den Export des gesamten Boards als JSON-Datei an. Kein Problem, denn es gibt da Werkzeug jq, mit dem man Abfragen auf JSON-Dateien machen kann, wenn man weiss, wie.

Da ich euch nicht mit Megabyte-grossen JSON-Dateien aus meinem Büro belästigen möchte, nehme ich als Beispiel eine kleine Datei aus dem ersten Artikel (test.json):

{
  "name": "Georg",
  "alter": 47,
  "verheiratet": false,
  "beruf": null,
  "kinder": [
    {
      "name": "Lukas",
      "alter": 19,
      "schulabschluss": "Gymnasium"
    },
    {
      "name": "Lisa",
      "alter": 14,
      "schulabschluss": null
    },
    {
      "name": "Marie",
      "alter": 18,
      "schulabschluss": "Realschule"
    }
  ]
}

Die Aufgabe lautet: Zeige alle Kinder, die älter als 15 Jahre sind und gebe den Namen und den Schulabschluss in einer Zeile aus. Zuerst einmal muss jq installiert werden: pamac install jq (oder ähnlich, abhängig von eurer Distro). Ob jq funktioniert, lässt sich mit diesem Kommando ermitteln: jq . test.json. Ihr solltet dann den kompletten Inhalt der JSON-Datei sehen.

Nun sollen zwei Felder aus dem Array kinder ausgegeben werden, z. B. mit diesem Kommando:

jq '.kinder[].name, .kinder[].alter' test.json

"Lukas"
"Lisa"
"Marie"
19
14
18

Meh, so war das nicht gemeint. Die Werte sollen in einer Zeile stehen:

jq '.kinder[].name + " " + (.kinder[].alter|tostring)' test.json

"Lukas 19"
"Lisa 19"
"Marie 19"
"Lukas 14"
"Lisa 14"
"Marie 14"
"Lukas 18"
"Lisa 18"
"Marie 18"

Hier passieren zwei Sachen. Zum einen werden Name und Alter konkateniert, mit einem Leerzeichen dazwischen. Da Alter jedoch ein Integer ist, muss dieser Wert in einen String umgewandelt werden. Jetzt fehlt nur noch der Filter:

jq '.kinder[]|.name + " besucht " + select(.alter>15).schulabschluss' test.json

"Lukas besucht Gymnasium"
"Marie besucht Realschule"

Auch hier gesehen wieder mehrere Sachen: Zuerst wird die gesamte Kinder-Liste an die nachfolgenden Befehle gepiped. Dadurch muss man nicht immer wieder .kinder[] voranstellen. Name und Schulabschluss werden konkateniert; eine Typ-Umwandlung ist nicht nötig, weil beide Werte Strings sind. Zwischendurch wird die Wertemenge auf diejenigen beschränkt, deren Alter grösser als 15 ist.

Mir ist es nicht gelungen, statt des Schulabschlusses das Alter auszugeben, weil dafür die Typ-Umwandlung benötigt wird. Das hier hat nicht funktioniert:

jq '.kinder[]|.name + " " + select(.alter>15)(.alter|tostring)' test.json 

Auch mit offensichtlichen Abwandlungen habe ich es nicht geschafft. Das Problem liegt hier: select(.alter>15)(.alter|tostring). Ich bin mir sicher, dass ihr eine Lösung dafür findet.

Fazit

jq ist ein mächtiges Werkzeug, wenn es um die Abfrage von JSON-Dateien geht. Doch die Lernkurve ist steil. Oft gibt es mehrere Wege, um zum Ziel zu kommen. In SQL ist die Lösung für diese Aufgabe ein Kinderspiel. Vermutlich wäre ich mit Python auch schneller zu einem Ergebnis gekommen. Doch das hängt von der eigenen Routine ab. Wer einmal im Jahr eine JSON-Datei abfragen möchte, sucht sich im Internet einen Wolf. Die Übung macht den Meister.

Gerne beende ich diesen Artikel mit der Frage, wie ihr es gelöst hättet.

Quelle: https://jqlang.github.io/jq/manual/v1.6/

Bildquelle: https://www.crio.do/blog/content/images/2021/06/What-is-JSON.png

Tags

JSON, jq, Abfrage, Query

Robert
Geschrieben von Robert am 18. Januar 2024 um 10:20

jq '.kinder[]|select(.alter>15).name + " (" + (.alter|tostring) + " Jahre) besucht " + .schulabschluss' test.json