Requêtage / recherche des données dans Grist

Bonjour,

j’ai créé et configuré une dizaine de tables dans Grist avec des relations entre elles.

Je m’interroge maintenant sur la possibilité de pouvoir requêter rapidement les données de ces différentes tables.

J’ai noté qu’il était possible de le faire via des requêtes SQL en utilisant le webhook Sql accessible depuis la console de l’API.

Cela étant, je me demande si il n’existe pas un moyen encore plus direct tel qu’un module de recherche intégré dans Grist qui fasse peu ou prou la même chose ?

Je suis preneur de toutes les pistes et trucs et astuces.

Merci par avance pour votre aide.

Bonjour,

Désolé, je n’ai pas très bien compris, où vous souhaiter « requêter » ? Ni à quoi ressemble votre MLD (modèle logique de données). Si vous pouvez donner qq exemples de la structure de vos tables (et notamment des liens de jointure entre vos tables avec vos clés étrangères).

  • Est ce que vous voulez écrire une formule Python dans une nouvelle table, qui construise cette jointure ?
  • Est ce que vous voulez calculer des agrégats (SUM, MOY, MIN, MAX…) dans une table Grist (GROUP BY) ?
  • Est ce que vous voulez construire un custom widget ?

Via formule Python

Dans une formule Python, j’écrirais qq chose comme ci-dessous, pour récuperer les lignes de la table « INDICATEUR » lié (jointure) avec la table « STRUCTURE ». Pour l’exemplen j’ai ajouté l’année et le mois mais cela peut être aussi d’autre clé étrangères (tables liées)

import json

table_source = INDICATEUR

# FK_STRUCTURE est une colonne "Référence" dans la table source (clé étrangère)
rows= table_source.lookupRecords(ANNEE=rec.ANNEE, MOIS=rec.MOIS, STRUCTURE=rec.FK_STRUCTURE)

# JSON output debug
dataset = []
for r in rows:
    dataset.append({
        "id": r.id,
        "year": int(r.ANNEE),
        "month": r.MOIS,
        "structure_code": str(r.STRUCTURE.CODE),
        "value": r.VALEUR
    })

return json.dumps(dataset, ensure_ascii=False, indent=2)

Via GRIST API javascript

Selon le volume de donnée, (si il est pas trop important) je ferais qq chose

  1. Extraction de toutes les données depuis les tables sources sélectionnés

    const desiredTables = [ 'TABLE1', 'TABLE2', 'TABLE3'];
    const raw = {};
    for (const id of desiredTables) {
        raw[id] = await grist.docApi.fetchTable(id);
    }
    
  2. Normalisation des jeux de données en lignes pour transformer le format Grist (par colonne). Il est plus agréable d’itérer une collection sous la forme d’un tableau classique d’objets Javascript ([ {col1: val, col2: val}, ... ]).

    function _normalizeTable(raw) {
      if (!raw) return [];
      const rows = [];
      for (const col of Object.keys(raw)) {
        raw[col].forEach((value, i) => {
          if (!rows[i]) rows[i] = {};
          rows[i][col] = value;
        });
      }
      return rows;
    }
    
  3. Le tout dans une fonction

    async function fetchAllData() {
        const desiredTables = [ 'TABLE1', 'TABLE2', 'TABLE3'];
        const raw = {};
        for (const id of desiredTables) {
            raw[id] = await grist.docApi.fetchTable(id);
        }
    
        return {
            table1: _normalizeTable(raw.TABLE1),
            table2: _normalizeTable(raw.TABLE2),
            table3: _normalizeTable(raw.TABLE3)
        };
    }
    
  4. Puis enfin on peut faire une jointure des tables selon son besoin (left, full, inner…) en parcourant les items (lignes) de la table.

function leftJoin(leftTable, rightTable, leftKey, rightKey) {
  const result = [];
  // Itération sur chaque ligne de la table à gauche
  for (const leftRow of leftTable) {
    let matchFound = false;

    // Recherche de correspondance dans la table de droite
    for (const rightRow of rightTable) {
      // La clé de joinutre pour l'exemple est minimaliste ici, elle peut etre plus complexe
      // et dépendre de plus d'items si besoin
      if (leftRow[leftKey] === rightRow[rightKey]) {
        
        // Ajout de la fusion des deux lignes dans le dataset final (result)
        const mergedRow = { ...leftRow, ...rightRow };
        result.push(mergedRow);
        matchFound = true;
      }
    }
    
    // Si aucune correspondance n'a été trouvé, on garde qd même la ligne de gauche (seule) 
    // conformément au principe de la jointure à gauche
    if (matchFound === false) {
      result.push(leftRow);
    }
  }

  return result;
}

Attention, ce n’est clairement pas une solution idéale présenté ici. C’est juste pour comprendre. Du poitn de vue de la performance, c’est catastrophique ! Si la table de gauche à 1000 lignes et la table de droite également , la condition de jointure est évalué 1 million de fois. Ce n’est pas avec 10 lignes de codes que l’on remplace un moteur SGBD relationnelle qui sert et qui est optimiser pour ca ^^. Mais il est possible d’optimiser (via un dictionnaire sur la table de droite par exemple, avant de lancer la boucle.

Tout dépend du besoin et contexte

Hello @vincent.blain,

mon besoin porte plus sur la possibilité de requêter des données dans les tables plutôt que dans l’élaboration des requêtes en elle-même.

Si je prends un exemple général avec une table initiale, une table secondaire liée à la table initiale et enfin une table tertiaire liée à la table secondaire, on aurait :

  • Table Centrale “Commandes” : Chaque enregistrement représente une commande unique passée par un client.
  • Table Secondaire “Lignes_Commande” (liée à “Commandes”) : Contient les articles achetés dans chaque commande. Une commande a plusieurs lignes.
  • Table Tertiaire “Options_Produit” (liée à “Lignes_Commande”) : Si un produit a des options (taille, couleur, gravure), ces détails sont stockés chacun dans une ligne d’”Options_Produit” et liés à une ligne de commande spécifique.

Je me demande par exemple comment consulter rapidement dans Grist la liste des commandes du mois passé et ayant des options produits avec la couleur jaune ?

Par “rapidement” j’entends sans avoir à configurer nécessairement une vue pour cela car c’est plus un besoin de recherche de données ponctuel.

On pourrait imaginer que la barre de recherche dans Grist permette de requêter ce type d’info via un langage de type SQL (vu que c’est possible via l’API) ou (mieux ?) quelle intègre un assistant IA permettant d’effectuer cette recherche directement.

Je ne sais pas si ma demande est plus claire ?

Bonjour, pour votre besoin j’utiliserais plutôt le widget barre de recherche, qui utilise des opérateurs booléens, très rapide : grist-widget/simplefilter at main · Varamil/grist-widget · GitHub

Par ailleurs pour les requêtes SQL, j’avais commencé à travailler sur un widget console SQL, mais il est en standby pour le moment

Effectivement au vu de la description, cela a l’air de répondre à mon besoin : je passe ce fil à résolu

Merci à tous les 2 pour vos réponses