Aller au contenu principal

JSON

La méga-brick JSON enchaîne plusieurs opérations sur des données JSON, dans l'ordre déclaré : aplatir une structure imbriquée en colonnes (flatten), parser une chaîne JSON en objet (parse) ou sérialiser des colonnes en une chaîne JSON (stringify).

Elle remplace les anciennes bricks Flatten JSON, From JSON et To JSON (voir Bricks héritées).

EntréesSorties
in : le flux de donnéesout : le flux transformé
remarque

Une opération dont la colonne cible n'existe pas dans le flux est ignorée silencieusement : le flux passe inchangé. En revanche, un JSON invalide (flatten, parse) fait échouer l'exécution.

flatten : aplatir une structure​

Déplie une colonne contenant un objet imbriqué (ou une chaîne JSON) en autant de colonnes que de champs. Les nouvelles colonnes sont préfixées du nom de la colonne d'origine, les niveaux étant joints par le séparateur.

ParamètreTypeDéfautDescription
columnstring—Colonne à aplatir (objet ou chaîne JSON).
separatorstring.Séparateur entre les niveaux imbriqués.
drop_sourcebooléentrueSupprime la colonne d'origine après aplatissement.
prefixstringle nom de la colonnePréfixe des colonnes produites. Vide = aucun préfixe, les clés donnent les noms.

Avant, colonne client :

idclient
1{"nom": "Dupont", "adresse": {"ville": "Lyon"}}

Après (separator: ".", drop_source: true) :

idclient.nomclient.adresse.ville
1DupontLyon

explode : éclater un tableau en lignes​

La seule opération qui change le nombre de lignes : chaque élément du tableau devient une ligne, l'entête étant recopiée sur chacune.

ParamètreTypeDéfautDescription
columnstring—Colonne qui porte le tableau.
pathstring(racine)Chemin pointé vers le tableau (facture.lignes).
keep_columnslistetoutesColonnes d'entête reportées sur chaque ligne.
output_namestring(vide)Colonne qui reçoit l'élément entier. Vide = l'élément est éclaté en colonnes.
prefix / separatorstring'' / .Nomment les colonnes issues de l'éclatement. Sans objet si output_name est renseigné.
drop_sourcebooléentrueSupprime la colonne source.
on_emptystringignorerignorer, conserver (garde l'entête seule) ou echouer.

Deux façons de sortir le détail​

Avec ID_FACTURE et une colonne ACTES portant [{"CODE_ACTE": "A1", "QUANTITE": 1}, {"CODE_ACTE": "A2", "QUANTITE": 3}] :

Éclaté en colonnes — sans output_name :

ID_FACTURECODE_ACTEQUANTITE
F-1A11
F-1A23

Gardé entier — output_name: LINE :

ID_FACTURELINE
F-1{'CODE_ACTE': 'A1', 'QUANTITE': 1}
F-1{'CODE_ACTE': 'A2', 'QUANTITE': 3}

Le second sert quand la ligne de détail doit voyager telle quelle : la repasser dans une boucle, l'écrire d'un bloc, l'ouvrir plus loin. L'élément est rangé comme une structure — celle que produit aussi parse — et reste donc lisible par la brick.

Le parcours en deux étapes​

Éclater, puis extraire — deux gestes qui se lisent et se règlent séparément :

explode   column: ACTES   keep_columns: [ID_FACTURE]   output_name: LINE
flatten column: LINE prefix: (vide)
ID_FACTURECODE_ACTEQUANTITE
F-1A11
F-1A23
Videz le préfixe sur la seconde étape

Sans cela, les colonnes sortent en LINE.CODE_ACTE : la colonne porteuse n'était qu'un intermédiaire, et il faudrait renommer colonne par colonne derrière.

Nommer les colonnes avant de les écrire en aval​

Les colonnes issues d'un aplatissement viennent du contenu du document, pas de la configuration : ni le studio ni le moteur ne peuvent les deviner. Chaque flatten et chaque explode porte donc son JSON d'exemple, replié sous le nom de la colonne qu'il ouvre.

L'exemple ne configure rien : il ne part jamais au runner, et ne change pas une ligne de ce que la brick fait. Il sert à annoncer les colonnes, pour qu'on cesse d'écrire de mémoire des noms qu'on ne découvrirait inexistants qu'à l'exécution.

Un exemple par colonne, pas un pour la brick

Dans un « éclater puis extraire », le premier geste voit le tableau et le second l'élément : ce ne sont pas les mêmes colonnes. Un exemple unique ne pouvait décrire que le premier, et le second n'annonçait rien.

Déclarer le type d'une colonne produite​

Les types d'un aplatissement sont devinés par pandas depuis les valeurs : un 1 sans guillemets sort en int64, un 0 de TVA aussi. Chaque colonne déduite porte donc un sélecteur de type, sous l'exemple.

Tant que rien n'est déclaré, il affiche « Deviné (Texte) » — et c'est une information, pas un réglage.

Un exemple ment souvent sans le vouloir

Un repr relu depuis une base écrit 'QUANTITE': '1', entre quotes, donc du texte — là où le document réel porte "QUANTITE": 1, un nombre. Le type deviné vient de l'exemple, pas de la donnée : voir « Texte » ne veut pas dire qu'on en aura. Il faut le déclarer.

Le type déclaré est appliqué — pas seulement annoncé. C'est le paramètre types de l'opération, et il part au runner :

flatten   column: LINE   prefix: (vide)   types: { QUANTITE: string }
sans typesavec types: { QUANTITE: string }
QUANTITE → 1 (entier)QUANTITE → '1' (texte)
Un réglage qui dit « Texte » doit produire du texte

Ces types n'ont d'abord servi qu'à l'affichage. C'était pire que pas de réglage du tout : le contrat de sortie enregistrait « Texte », le flux portait un entier, et la brick d'aval refusait l'entrée —

Contrat de schéma non respecté — « QUANTITE_STR » attendu Texte (string)
mais reçu int64

— sur un écart que l'écran avait lui-même créé.

Un type posé sur une colonne que le document ne porte plus est simplement ignoré : le réglage est périmé, pas fautif.

Ce qu'on fait d'une valeur illisible​

on_cast_errorEffet
echouer (défaut)La brick s'arrête, en nommant la colonne.
ecarterLa ligne part sur la sortie « Non convertible », les autres continuent converties.

Arrêter est le défaut : sur un flux interne, un mauvais type est un défaut de programme. Sur des données venues du dehors, non — dix mille factures dont trente portent un montant illisible ne doivent pas être perdues tout entières.

La sortie « Non convertible » porte les valeurs telles qu'elles sont arrivées — c'est ce qui a été reçu qu'il faut lire pour comprendre — plus une colonne _cast_error qui dit pourquoi. Les motifs d'une même ligne y sont réunis, séparés par ; :

« QUANTITE » ne se lit pas comme « integer » : 'trop'; « MONTANT_HT » ne se lit pas comme « integer » : 'cher'

Les rendre un par un obligerait à suivre la même ligne de rejet en rejet pour savoir tout ce qui cloche, et à recommencer après chaque correction.

Une case vide n'est pas une case illisible

Il n'y avait rien à convertir, donc rien n'a échoué : la ligne continue et la colonne reste vide. cast_empty_ok à faux la rejette au contraire — utile quand la colonne est censée être toujours remplie, et que son vide est justement l'anomalie qu'on cherche. Le motif dit alors « est vide », pas « ne se lit pas ».

La sortie « Non convertible » est toujours émise, même vide. Une sortie qui n'existerait que les jours de rejet obligerait l'aval à se demander si rien n'a été écarté ou si la branche n'a pas tourné.

L'onglet Sortie montre le résultat de la chaîne entière, toutes opérations enchaînées.

Les littéraux Python sont lus

explode, parse et flatten acceptent le JSON et le repr Python — quotes simples, True/None — la forme ordinaire d'une liste relue depuis une base. Un texte qui n'est ni l'un ni l'autre arrête la brick, en nommant la colonne.

parse : chaîne JSON vers objet​

Convertit une colonne contenant du JSON sous forme de chaîne en objet manipulable par les opérations suivantes (par exemple un flatten juste après).

ParamètreTypeDéfautDescription
columnstring—Colonne contenant la chaîne JSON.
output_namestringcolonne sourceColonne de sortie (par défaut, remplace la colonne source).

Avant : payload = "{\"statut\": \"ok\"}" (chaîne). Après : payload est un objet dont les opérations suivantes peuvent lire les champs.

stringify : colonnes vers chaîne JSON​

Sérialise plusieurs colonnes en une colonne contenant un objet JSON par ligne. Pratique avant un export vers une API ou une colonne jsonb.

ParamètreTypeDéfautDescription
columnsliste—Colonnes à inclure dans l'objet JSON (seules celles présentes dans le flux sont prises).
output_namestring—Colonne de sortie (requis ; sans elle, l'opération est ignorée).

Avant :

nomville
DupontLyon

Après (columns: [nom, ville], output_name: doc) :

nomvilledoc
DupontLyon{"nom": "Dupont", "ville": "Lyon"}

Bonnes pratiques​

  • Ordre des opérations : parse avant flatten n'est pas nécessaire, flatten parse lui-même les chaînes JSON. Utilisez parse seul quand vous voulez garder l'objet sans l'aplatir.
  • Séparateur : gardez . sauf si vos champs JSON contiennent déjà des points ; un séparateur _ produit des noms de colonnes plus faciles à requêter en SQL.
  • Exemple : donnez-le sur l'opération qui ouvre la colonne, pas sur la brick — dans un « éclater puis extraire », les deux gestes ne voient pas les mêmes colonnes.
  • Colonnes de sortie : après un flatten, une brick Colonnes permet de renommer, supprimer, ou ne garder que les colonnes générées.

Voir aussi : Bricks héritées.