Intermédiaire8 min de lecture

Relations un-à-plusieurs dans DynamoDB

Un plan de contrôle SaaS a presque toujours une hiérarchie de conteneurs : un workspace possède de nombreux projets. En SQL, tu poserais une clé étrangère workspace_id sur la table des projets, puis un JOIN.

DynamoDB n'a ni jointures ni clés étrangères, donc la relation doit vivre dans le schéma de clés lui-même. Bien fait, « charger un workspace et chaque projet qu'il contient » devient un seul Query au lieu d'une lecture suivie d'un scan.

Comment modéliser une relation un-à-plusieurs dans DynamoDB ?

Donne au parent et à tous ses enfants la même pour qu'ils partagent une seule , puis différencie-les avec la clé de tri. DynamoDB n'a ni jointures ni clés étrangères, donc la relation vit dans le schéma de clés lui-même. Charger un parent plus chacun de ses enfants devient alors un seul Query au lieu d'une jointure.

  • Modélise les lectures, pas les entités. La relation un-à-plusieurs n'existe que pour servir « lister les projets d'un workspace » — façonne les clés autour de cette requête.
  • Encode le parent dans la de l'enfant. Donne au workspace et à tous ses projets la même valeur de clé de partition pour qu'ils atterrissent dans une seule .
  • La lecture de liste devient alors un seul Query. Le parent et ses enfants reviennent ensemble — pas de jointure, pas de second aller-retour (un Query renvoie jusqu'à 1 Mo par page, en paginant via LastEvaluatedKey au-delà).
  • Surveille la . Un seul locataire énorme concentre tout son trafic sur une seule partition ; un workspace gigantesque peut nécessiter une clé partitionnée et une lecture en éventail.

Le modèle d'accès, d'abord

La modélisation DynamoDB commence par le modèle d'accès, pas par les entités — la même discipline derrière la conception à table unique. Avant de choisir la moindre clé, écris les lectures que l'application émet réellement :

  • Obtenir les paramètres d'un workspace.
  • Lister chaque projet d'un workspace, du plus récent au plus ancien.
  • Obtenir un projet précis par son id.

La relation « un workspace, plusieurs projets » ne compte que grâce à la lecture nº 2. Si tu n'avais jamais besoin de lister ensemble les projets d'un workspace, tu ne modéliserais pas la relation du tout — tu stockerais les projets indépendamment.

Donc la question n'est jamais « comment représenter le un-à-plusieurs ? » dans l'abstrait. C'est « quelles requêtes cette relation doit-elle servir ? » Réponds à ça, puis façonne les clés autour.

Pourquoi une clé étrangère n'aidera pas ici

Dans DynamoDB, chaque GetItem et chaque Query cible une clé de partition, et le service hache cette clé pour localiser la partition qui contient l'item.

AWS le dit directement dans la doc Core Components : la valeur de la clé de partition est l'entrée d'une fonction de hachage interne qui décide où vivent les données.

Ce placement basé sur le hachage est l'héritage du papier original de 2007 Dynamo: Amazon's Highly Available Key-value Store, où le hachage cohérent distribue les clés entre les nœuds.

Un simple attribut workspace_id sur un item projet est invisible à cette machinerie — DynamoDB ne peut pas le « suivre ».

Pour récupérer les items liés en une seule requête, l'identité du parent doit être encodée dans la clé de partition du projet, afin que tous les items d'un workspace hachent vers la même partition et qu'un seul Query puisse les balayer.

Exemple concret : workspaces et projets

Utilise un schéma de clés générique et surchargé. Appelle la clé de partition EntityRef et la clé de tri Detail. L'identité du workspace va dans EntityRef pour à la fois l'item workspace et chaque projet qu'il contient :

EntityRefDetailattributes
WS#acmeMETAdisplayName, region, seatLimit
WS#acmePROJ#2026-0007title, status, createdBy
WS#acmePROJ#2026-0042title, status, createdBy
WS#acmePROJ#2026-0118title, status, createdBy
WS#globexMETAdisplayName, region, seatLimit
WS#globexPROJ#2026-0009title, status, createdBy

Le workspace et tous ses projets partagent EntityRef = "WS#acme", formant ainsi une seule collection d'items qui vit ensemble sur une même partition.

La clé de tri Detail les sépare : META est l'enregistrement du workspace, et chaque projet porte un préfixe PROJ# avec un id complété par des zéros et ordonné dans le temps, si bien que les projets se trient naturellement.

Visuellement, le parent et ses enfants s'empilent à l'intérieur d'une partition, ordonnés par la clé de tri :

Partition : EntityRef = WS#acmeMETA réglages du workspacePROJ#2026-0007PROJ#2026-0042PROJ#2026-0118

Un seul Query sur EntityRef = "WS#acme" balaie toute la pile — le parent plus chaque enfant — en une seule lecture.

Maintenant, chacun des trois modèles d'accès se réduit à un seul appel :

  • Paramètres du workspaceGetItem(EntityRef="WS#acme", Detail="META").
  • Lister les projets du plus récent au plus ancienQuery(EntityRef="WS#acme") avec Detail begins_with "PROJ#", exécuté en ordre décroissant (ScanIndexForward = false).
  • Un projetGetItem(EntityRef="WS#acme", Detail="PROJ#2026-0042").

Le deuxième est tout l'intérêt : le parent et ses enfants reviennent d'un seul Query, pas de jointure ni de second aller-retour — DynamoDB renvoie jusqu'à 1 Mo par page et te remet un LastEvaluatedKey pour récupérer le reste. C'est le coup que tu ne peux pas jouer avec un attribut de clé étrangère et un Scan.

Écrire cette condition begins_with à la main est fastidieux — la syntaxe de la condition de clé et de l'expression de projection mord.

Le DynamoDB Expression Builder génère la KeyConditionExpression, les tables de placeholders #name/:value, et un snippet SDK prêt à l'emploi pour que tu n'aies pas à lutter contre la grammaire :

KeyConditionExpression     "#er = :er AND begins_with(#d, :p)"
ExpressionAttributeNames   { "#er": "EntityRef", "#d": "Detail" }
ExpressionAttributeValues  { ":er": "WS#acme", ":p": "PROJ#" }

Inspecter la collection d'items dans DynoTable

Le bénéfice de cette disposition est visuel : chaque ligne partageant un EntityRef est le workspace plus ses enfants, côte à côte.

DynoTable les regroupe pour que tu voies la relation un-à-plusieurs comme un seul bloc contigu au lieu de la deviner à travers des tables séparées.

L'item META du workspace et ses enfants PROJ# regroupés en une seule collection d'items dans la vue table de DynoTable.
L'item META du workspace et ses enfants PROJ# regroupés en une seule collection d'items dans la vue table de DynoTable.

Pièges et la forme alternative

Quelques points à surveiller :

  • Partitions à chaud. Chaque item d'un workspace vit sur une seule partition, donc un seul locataire très gros ou très actif concentre le trafic. Le comportement de capacité adaptative décrit par AWS absorbe un déséquilibre modéré, mais un workspace avec des millions de projets peut nécessiter une clé partitionnée (par ex. WS#acme#01 … #10) et une lecture en éventail.
  • Taille de la collection d'items. Avec un index secondaire local, la collection d'items d'une seule partition est plafonnée à 10 Go ; sans LSI, il n'y a pas de telle limite. Si tu pèses les types d'index ici, vois GSI vs LSI.
  • Vise le Query, jamais le Scan. Toute la conception existe pour que tu puisses Query une seule partition. Retomber sur un Scan filtré pour « trouver les projets d'un workspace » jette le modèle à la poubelle et lit la table entière — le piège couvert dans Query vs Scan.

Si tu as réellement besoin de lister les projets à travers les workspaces (disons, tous les projets status = ACTIVE globalement), la table de base ne peut pas répondre à ça — sa clé de partition est à portée de workspace.

C'est le travail d'un index secondaire qui re-partitionne les projets sur un autre attribut, pas d'un remodelage de cette relation.

Étapes suivantes

Modélise les modèles d'accès, encode le parent dans la clé de partition de l'enfant, et la lecture un-à-plusieurs est un seul Query. Construis et valide la condition de clé avec le DynamoDB Expression Builder — et si tu préfères partir des modèles d'accès eux-mêmes, l'outil de Single-Table Design gratuit ébauche le plan PK/SK/GSI avec des items d'exemple.

Ensuite, télécharge DynoTable pour charger ce schéma, parcourir en direct la collection d'items workspace→projets, et confirmer que chaque requête fait exactement une lecture. Si tu préfères voir les workspaces et les projets comme une vue relationnelle jointe, le SQL Workbench de DynoTable exécute ce JOIN aussi.

Mis à jour

Essaie cette conception de façon interactive

Esquisse tes entités et tes motifs d’accès dans l’outil gratuit de Single-Table Design DynamoDB — il suggère des modèles de clés PK/SK, prévisualise les collections d’items et montre quels motifs nécessitent un GSI.

Ouvrir l’outil de Single-Table Design