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.
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:sumgroupBy 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.
L'ordre est champ:fonction, et l'inverser échoue en silence. ?aggregate=sum:amount est analysé comme le champ sum avec la fonction amount, qui n'est pas une fonction connue : l'entrée est donc écartée. Si toutes les entrées sont écartées, le paramètre devient absent et la requête renvoie 200 sans aucune agrégation — sans la moindre erreur pour vous le signaler.
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.
{
"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.
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".
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: descDeux 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. |
?view= n'applique que les filtres et les tris. Les fields et le groupBy d'une vue sont honorés par le point de terminaison dédié GET /api/tables/:tableId/views/:viewId/records, pas par la liste des enregistrements avec un paramètre view. Si vous avez besoin de la configuration complète de la vue, appelez le point de terminaison de la vue.
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.
GET /api/tables/tasks/records?includeDeleted=true
GET /api/tables/tasks/records?deleted=trueVoir Suppression douce et restauration pour le flux de récupération complet.
Pages associées
- Filtrage, tri et pagination — le reste de la grammaire des requêtes de liste.
- Vues de table — déclarer les configurations de filtre/tri/champs enregistrées.
- Suppression douce et restauration — corbeille, restauration et cascades.
- Présentation des enregistrements — enveloppe de liste et règles transversales.
- Analytique — des agrégats prêts à l'emploi sur l'usage plutôt que sur les enregistrements.
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.