Query Builder

Fonctions JSON dans le Query Builder

Utilisez JSONValue, JSONExtract et JSONContains pour interroger des champs JSON dans vos requêtes Dodock.

Fonctions JSON dans le Query Builder

Dodock expose trois fonctions SQL spécialisées pour manipuler des champs contenant des données JSON : JSONValue, JSONExtract et JSONContains. Ces fonctions permettent d'extraire ou de filtrer des valeurs imbriquées dans un champ JSON directement depuis le Query Builder Python, sans avoir à charger l'ensemble des documents en mémoire.

Ces fonctions reposent sur les fonctions JSON natives de MariaDB (JSON_VALUE, JSON_EXTRACT, JSON_CONTAINS). Elles nécessitent MariaDB 10.2.3 ou supérieur.

Import

from frappe.query_builder.functions import JSONValue, JSONExtract, JSONContains

JSONValue

JSONValue(champ, chemin) extrait une valeur scalaire (chaîne, nombre, booléen) depuis un champ JSON en suivant un chemin JSONPath.

Syntaxe

JSONValue(champ, chemin_jsonpath)
ParamètreTypeDescription
champColonne DodockChamp du DocType contenant la valeur JSON
chemin_jsonpathstrExpression JSONPath commençant par $

Exemple : filtrer sur une valeur imbriquée

Soit un DocType Profile avec un champ preferences_json stockant :

{"notifications": {"email": true, "sms": false}, "language": "en"}
import frappe
from frappe.query_builder.functions import JSONValue

Profile = frappe.qb.DocType("Profile")

resultats = (
    frappe.qb.from_(Profile)
    .select(
        Profile.customer_name,
        JSONValue(Profile.preferences_json, "$.notifications.email").as_("notif_email"),
        JSONValue(Profile.preferences_json, "$.language").as_("langue"),
    )
    .where(JSONValue(Profile.preferences_json, "$.notifications.email") == "true")
).run(as_dict=True)

Cette requête retourne uniquement les profils dont les notifications par e-mail sont activées, en exposant directement les valeurs extraites comme colonnes nommées.

JSONExtract

JSONExtract(champ, chemin) extrait une valeur ou un fragment JSON (y compris un tableau ou un objet imbriqué) depuis un champ JSON. Contrairement à JSONValue, le résultat peut être un tableau JSON ou un objet, pas seulement une valeur scalaire.

Syntaxe

JSONExtract(champ, chemin_jsonpath)

Exemple : extraire un tableau imbriqué

Soit un DocType Sales Order avec un champ applied_discounts_json stockant :

{"codes": ["WELCOME10", "FREESHIP", "VIP"]}
from frappe.query_builder.functions import JSONExtract

SalesOrder = frappe.qb.DocType("Sales Order")

codes = (
    frappe.qb.from_(SalesOrder)
    .select(
        SalesOrder.name,
        JSONExtract(SalesOrder.applied_discounts_json, "$.codes").as_("codes_remise"),
    )
).run(as_dict=True)

Le résultat de JSONExtract sur un tableau est une chaîne JSON de type ["WELCOME10", "FREESHIP", "VIP"], que vous pouvez ensuite passer à JSONContains.

JSONContains

JSONContains(cible, valeur) vérifie si une valeur est contenue dans un document ou un tableau JSON. Elle est particulièrement utile pour filtrer des listes stockées en JSON.

Syntaxe

JSONContains(cible, valeur)
ParamètreTypeDescription
cibleColonne ou résultat de JSONExtractFragment JSON dans lequel chercher
valeurstrValeur JSON à rechercher (encodée en chaîne)

Exemple : filtrer les commandes contenant un code promo

import frappe
from frappe.query_builder.functions import JSONContains, JSONExtract

SalesOrder = frappe.qb.DocType("Sales Order")

commandes = (
    frappe.qb.from_(SalesOrder)
    .select(SalesOrder.name, SalesOrder.customer)
    .where(
        JSONContains(
            JSONExtract(SalesOrder.applied_discounts_json, "$.codes"),
            '"FREESHIP"',
        )
    )
).run(as_dict=True)
Attention au guillemets : pour rechercher une chaîne dans un tableau JSON, la valeur doit être encodée comme valeur JSON valide, donc entourée de guillemets doubles : '"FREESHIP"' et non 'FREESHIP'.

Combiner les fonctions

Les trois fonctions sont composables. Voici un exemple réel combinant JSONExtract et JSONContains pour filtrer les commandes client ayant bénéficié de la livraison gratuite :

import frappe
from frappe.query_builder.functions import JSONContains, JSONExtract, JSONValue

SalesOrder = frappe.qb.DocType("Sales Order")
Profile = frappe.qb.DocType("Profile")

# Commandes avec livraison gratuite pour les clients ayant activé les notifications e-mail
resultats = (
    frappe.qb.from_(SalesOrder)
    .inner_join(Profile)
    .on(SalesOrder.customer == Profile.name)
    .select(SalesOrder.name, SalesOrder.customer, SalesOrder.grand_total)
    .where(
        JSONContains(
            JSONExtract(SalesOrder.applied_discounts_json, "$.codes"),
            '"FREESHIP"',
        )
    )
    .where(JSONValue(Profile.preferences_json, "$.notifications.email") == "true")
).run(as_dict=True)

Référence rapide

FonctionÉquivalent SQLRetourneCas d'usage typique
JSONValue(champ, chemin)JSON_VALUE()Valeur scalaireLire $.language, $.price
JSONExtract(champ, chemin)JSON_EXTRACT()Valeur ou fragment JSONExtraire un tableau $.codes
JSONContains(cible, valeur)JSON_CONTAINS()0 ou 1Vérifier la présence dans un tableau

Ressources complémentaires