Relacionamentos um-para-muitos em DynamoDB
Um plano de controle SaaS quase sempre tem uma hierarquia de contenção: um espaço de trabalho
possui muitos projetos. Em SQL você colocaria uma chave estrangeira workspace_id no
tabela de projetos e JOIN.
DynamoDB não tem junções nem chaves estrangeiras, então o relacionamento tem que viver no
esquema chave em si. Feito corretamente, "carregue um espaço de trabalho e todos os projetos dentro dele"
torna-se um único Query em vez de uma leitura mais uma varredura de acompanhamento.
Como você modela um relacionamento um-para-muitos em DynamoDB?
Dê aos pais e a todos os seus filhos o mesmoentão eles compartilham ume diferencie-os com a chave de classificação. DynamoDB não possui junções ou chaves estrangeiras, portanto o relacionamento reside no próprio esquema de chave. Carregar um pai mais cada filho torna-se um único Query em vez de uma junção.
- Modele as leituras, não as entidades. O relacionamento um-para-muitos só existe para servir "listar os projetos de um espaço de trabalho" — molde as chaves em torno dessa consulta.
- Codifique o pai no filho. Dê o espaço de trabalho e tudo ele projeta o mesmo valor de chave de partição para que caiam em um .
- Então a lista lida é uma
Query. Pai mais seus filhos voltam juntos — sem junção, sem segunda viagem de ida e volta (umQueryretorna até 1 MB por página, paginando viaLastEvaluatedKeyalém disso). - Assista ao. Um grande inquilino concentra todo o seu tráfego em um partição; um espaço de trabalho gigante pode precisar de uma chave fragmentada e de uma leitura em leque.
O padrão de acesso, primeiro
A modelagem DynamoDB prioriza o padrão de acesso, não a entidade – a mesma disciplina por trás do design de tabela única. Antes de escolher qualquer chave, anote as leituras que o aplicativo realmente emite:
- Obtenha as configurações de um espaço de trabalho.
- Liste todos os projetos em um espaço de trabalho, começando pelos mais recentes.
- Obtenha um projeto específico por id.
O relacionamento “um espaço de trabalho, muitos projetos” só importa por causa da leitura nº 2. Se você nunca precisasse listar os projetos de um espaço de trabalho, você não modelaria o relacionamento - você armazenaria projetos de forma independente.
Portanto, a questão nunca é “como posso representar um para muitos?” no abstrato. É "quais consultas esse relacionamento deve atender?" Responda isso e depois molde as teclas em torno disso.
Por que uma chave estrangeira não ajudará aqui
Em DynamoDB cada GetItem e Query tem como alvo uma chave de partição, e o
service faz hash dessa chave para localizar a partição que contém o item.
AWS diz isso diretamente nos Componentes principais docs: o valor da chave de partição é a entrada para uma função hash interna que decide onde os dados ficam.
Esse posicionamento baseado em hash é a herança do _Dynamo original de 2007: Artigo de armazenamento de valor-chave altamente disponível da Amazon, onde hashing consistente distribui chaves entre nós.
Um atributo workspace_id vazio em um item do projeto é invisível para aquele
maquinaria — DynamoDB não pode "segui-la".
Para buscar itens relacionados em uma solicitação, a identidade do pai deve ser codificada em
a chave de partição do projeto, para que todos os itens de um espaço de trabalho sejam hash para o mesmo
partição e um Query pode varrê-las.
Exemplo prático: espaços de trabalho e projetos
Use um esquema de chave genérico e sobrecarregado. Chame a chave de partição EntityRef e o
chave de classificação Detalhe. A identidade do espaço de trabalho vai para EntityRef para ambos os
item do espaço de trabalho e todos os projetos sob ele:
| EntityRef | Detail | attributes |
|---|---|---|
| WS#acme | META | displayName, region, seatLimit |
| WS#acme | PROJ#2026-0007 | title, status, createdBy |
| WS#acme | PROJ#2026-0042 | title, status, createdBy |
| WS#acme | PROJ#2026-0118 | title, status, createdBy |
| WS#globex | META | displayName, region, seatLimit |
| WS#globex | PROJ#2026-0009 | title, status, createdBy |
O espaço de trabalho e todos os seus projetos compartilham EntityRef = "WS#acme", então eles formam um
coleção de itens únicos vivendo juntos em uma partição.
A chave de classificação Detail os separa: META é o registro do espaço de trabalho, e cada
projeto carrega um prefixo PROJ# com um ID ordenado por tempo e preenchido com zeros para que os projetos
classifique naturalmente.
Visualmente, o pai e seus filhos são empilhados dentro de uma partição, ordenados pelo chave de classificação:
Um Query em EntityRef = "WS#acme" varre toda a pilha - pai mais cada
criança - em uma única leitura.
Agora, cada um dos três padrões de acesso se reduz a uma chamada:
- Configurações do espaço de trabalho —
GetItem(EntityRef="WS#acme", Detail="META"). - Listar os projetos mais recentes —
Query(EntityRef="WS#acme")comDetalhe begins_with "PROJ#", executado em ordem decrescente (ScanIndexForward = falso). - Um projeto —
GetItem(EntityRef="WS#acme", Detail="PROJ#2026-0042").
O segundo é o ponto. O pai e seus filhos voltam de
um Query, sem junção e sem segunda viagem de ida e volta — DynamoDB retorna até 1 MB
por página e entrega a você um LastEvaluatedKey para buscar o resto. Esse é o movimento
você não pode fazer isso com um atributo de chave estrangeira e um Scan.
Escrever essa condição begins_with manualmente é complicado - a condição-chave e
mordidas de sintaxe de expressão de projeção.
O DynamoDB Expression Builder gera
o KeyConditionExpression, os mapas de espaço reservado #name/:value e um
snippet do SDK pronto para execução para que você não lute contra a gramática:
KeyConditionExpression "#er = :er AND begins_with(#d, :p)"
ExpressionAttributeNames { "#er": "EntityRef", "#d": "Detail" }
ExpressionAttributeValues { ":er": "WS#acme", ":p": "PROJ#" }
Inspecione a coleção de itens em DynoTable
Cada linha que compartilha um EntityRef é o
espaço de trabalho mais seus filhos, sentados um ao lado do outro.
DynoTable os agrupa para que você veja o relacionamento um-para-muitos como um relacionamento contíguo bloquear em vez de adivinhar em tabelas separadas.

Armadilhas e a forma alternativa
Algumas coisas para observar:
- Partições ativas. Cada item de um espaço de trabalho reside em uma partição, portanto,
um único inquilino muito grande ou muito ocupado concentra o tráfego. O
capacidade adaptativa
comportamento AWS descreve absorve inclinação moderada, mas um espaço de trabalho com milhões de
os projetos podem precisar de uma chave fragmentada (por exemplo,
WS#acme#01… #10) e uma leitura de fan-out. - Tamanho da coleção de itens. Com um índice secundário local, uma única partição a coleta de itens é limitada a 10 GB; sem um LSI não existe tal limite. Se você está pesando tipos de índice aqui, veja GSI vs LSI.
- Alcance
Query, nuncaScan. Todo o design existe para que você possaQueryuma partição. Voltando a umScanfiltrado para "encontrar um espaço de trabalho projetos" joga o modelo fora e lê a tabela inteira - a armadilha coberta em Query vs Scan.
Se você realmente precisa listar projetos em espaços de trabalho (digamos, todos
status = ACTIVE projeta globalmente), a tabela base não pode responder a isso - é
a chave de partição tem escopo no espaço de trabalho.
Esse é um trabalho para um índice secundário que reparticiona projetos em um local diferente. atributo, não para remodelar esse relacionamento.
Próximos passos
Modele os padrões de acesso, codifique o pai na chave de partição do filho e
a leitura um-para-muitos é um único Query. Construa e valide a condição chave
com o DynamoDB Expression Builder — e
se você preferir começar pelos próprios padrões de acesso, o acesso gratuito
Ferramenta de design de tabela única elabora o
Plano PK/SK/GSI com itens de exemplo.
Então download DynoTable para carregar este esquema, navegue no
espaço de trabalho→projetos coleção de itens ativa e confirme se cada consulta faz exatamente uma
leia. Se você preferir ver espaços de trabalho e projetos como uma visão relacional e conjunta,
DynoTable's SQL Workbench executa esse JOIN também.


