Skip to main content
Voir en Markdown

Regroupement et vues enregistrées

Trois façons de tirer davantage d'une seule requête de liste : la synthétiser, réutiliser une configuration stockée, et atteindre les lignes supprimées.

Regroupement et agrégation

groupBy partitionne les enregistrements selon la valeur d'un champ ; aggregate calcule des fonctions de synthèse. Combinés, ils produisent des synthèses groupées, comme le montant total par statut.

code
GET /api/tables/orders/records?groupBy=status
GET /api/tables/orders/records?groupBy=region,status
GET /api/tables/orders/records?aggregate=amount:sum,amount:count,quantity:avg
GET /api/tables/orders/records?groupBy=status&aggregate=amount:sum

groupBy accepte une liste de champs séparés par des virgules, trois au maximum, du plus externe au plus interne : ?groupBy=region,status partitionne par région, puis par statut à l'intérieur de chaque région. Chaque champ nommé doit exister sur la table et être lisible par l'appelant — un niveau nommant un champ que vous ne pouvez pas lire renvoie 404, exactement comme un champ unique illisible, car un en-tête de groupe révélerait sinon les valeurs distinctes de ce champ.

Chaque entrée d'aggregate s'écrit champ:fonction — le champ d'abord, la fonction ensuite. Les fonctions prises en charge sont sum, count, avg, min et max.

Une forme JSON est également acceptée : ?aggregate={"count":true,"sum":["amount"]}.

Sans aggregate, groupBy renvoie groups: [{ name, path, count }]. Avec, chaque groupe porte en plus aggregations, et la réponse porte toujours les aggregations de l'ensemble des résultats au niveau racine : une seule requête répond donc à la fois « par groupe » et « au global », sans imposer de choisir.

path contient la valeur du groupe à chaque niveau, du plus externe au plus interne, et se termine par son propre name. Il existe parce que la valeur d'un groupe cesse d'être une clé dès que groupBy nomme plus d'un champ : deux régions peuvent chacune contenir un groupe shipped, et un compte ne portant que name ne peut pas dire duquel il parle.

app.json
{
  "records": [/* … */],
  "groups": [
    // Niveau 1 — une entrée par région.
    {
      "name": "EMEA",
      "path": ["EMEA"],
      "count": 42,
      "aggregations": { "sum": { "amount": 5100 } },
    },
    {
      "name": "AMER",
      "path": ["AMER"],
      "count": 18,
      "aggregations": { "sum": { "amount": 2300 } },
    },
    // Niveau 2 — une entrée par statut À L'INTÉRIEUR de chaque région.
    {
      "name": "shipped",
      "path": ["EMEA", "shipped"],
      "count": 30,
      "aggregations": { "sum": { "amount": 4200 } },
    },
    {
      "name": "pending",
      "path": ["EMEA", "pending"],
      "count": 12,
      "aggregations": { "sum": { "amount": 900 } },
    },
    {
      "name": "shipped",
      "path": ["AMER", "shipped"],
      "count": 18,
      "aggregations": { "sum": { "amount": 2300 } },
    },
  ],
  "aggregations": { "sum": { "amount": 7400 } },
}

groups porte une entrée par groupe à chaque niveau nommé, dans un tableau plat ordonné par profondeur : d'abord tous les groupes de niveau 1, puis tous ceux de niveau 2, et ainsi de suite. Ce n'est pas un arbre : pour en construire un, répartissez les entrées selon path.length et rattachez chacune à son parent via path.slice(0, -1). Un groupBy à un seul champ renvoie des chemins à une entrée, si bien qu'un lecteur qui s'appuie sur name seul continue de fonctionner sans changement.

Les chiffres se recomposent d'un niveau à l'autre : les groupes de niveau 2 d'un même parent totalisent celui-ci, et les groupes de niveau 1 totalisent les aggregations racines.

Chaque count et chaque agrégation décrit l'ensemble des résultats filtrés, et non la page renvoyée à côté : les chiffres ne bougent pas d'une page à l'autre pour une même requête, à quelque niveau que ce soit. Un groupe dont toutes les lignes tombent sur une page ultérieure figure malgré tout dans groups.

Vues enregistrées

Une vue regroupe un arbre de filtres et un ordre de tri sous un identifiant stable : une requête récurrente tient donc en un paramètre plutôt qu'en une expression réencodée à chaque appel.

code
GET /api/tables/tasks/records?view=2

?view= s'apparie sur l'id de la vue ou sur son name. Une valeur ne correspondant ni à l'un ni à l'autre — ou toute référence de vue sur une table qui n'en déclare aucune — renvoie 404 NOT_FOUND avec "View '<x>' not found".

app.yaml
tables:
  - id: 1
    name: tasks
    views:
      - id: 2
        name: Active Tasks
        filters:
          and:
            - field: status
              operator: in
              value: [todo, in_progress]
        sorts:
          - field: priority
            direction: desc

Deux règles régissent l'interaction entre les paramètres explicites et la vue, et elles diffèrent :

Aspect Comportement
filter Fusionné avec le filtre de la vue par and — la requête ne peut que restreindre.
sort Remplace entièrement le tri de la vue lorsqu'il est présent.
fields La configuration de champs de la vue est ignorée sur ce point de terminaison.
groupBy Le regroupement de la vue est ignoré sur ce point de terminaison.

Inclure les enregistrements supprimés

Les lignes supprimées en douceur sont exclues par défaut. Deux paramètres permettent de les atteindre :

Paramètre Résultat
?includeDeleted=true Lignes actives et supprimées dans un même listing.
?deleted=true Lignes supprimées uniquement — un listing de corbeille.

includeDeleted est comparé à la chaîne exacte true ; toute autre valeur, y compris only, est traitée comme « exclure les supprimées ». La corbeille seule s'obtient par ?deleted=true, ou via le point de terminaison dédié GET /api/tables/:tableId/trash.

code
GET /api/tables/tasks/records?includeDeleted=true
GET /api/tables/tasks/records?deleted=true

Voir Suppression douce et restauration pour le flux de récupération complet.

Pages associées

Dernière mise à jour 1 septembre 2026

Cette documentation a été rédigée avec de l'IA : des erreurs ou du contenu obsolète sont donc possibles. Sovrium est en bêta. Les contributions et corrections sont les bienvenues.

Construit avec Sovrium