Das Type-Attribut in DynamoDB
In SQL ist die Tabelle einer Row ihr Typ — eine Row in documents ist ein
Document. Eine DynamoDB-Single-Table mischt jede Entity unter einem Schema, also
trägt ein Item keine eingebaute Antwort auf „was ist das?“.
Das Type-Attribut gibt diese Antwort zurück: ein plainer String auf jedem Item, der die Entity benennt, die es repräsentiert.
Was ist das Type-Attribut in DynamoDB?
Das Type-Attribut ist ein plainer String, den du auf jedes Item stempelst — wie
EntityType: "Document" — und der die Entity benennt, die dieses Item
repräsentiert. Weil eine Single Table
viele Entities unter einem Schema mischt, tragen Items keinen eingebauten Typ.
Der Type stellt ihn wieder her, sodass dein Code Rows identifiziert, einen GSI
auf eine Entity filtert und Migrationen überlebt.
- Stempele einen Type auf jeden Write. Ein Attribut —
EntityType: "Document"— auf jedes Item, keine Exceptions. Es kostet ein paar Bytes und spart dir später. - Es identifiziert Entities in einer gemischten Partition. Eine
Queryliefert Workspaces, Documents und Comments zusammen; der Type sagt deinem Code, was was ist, ohne Key-Prefixes zu parsen. - Es treibt Single-Entity-Filtering auf einem . Projeziere den Type in einen Index und du kannst einen überladenen Index auf genau einen Entity- Typ verengen.
- Es ist dein Escape Hatch für Migrationen. Wenn du exportierst, um zu remodeln oder eine Entity in ihre eigene Tabelle zu heben, ist der Type die Spalte, nach der du splittest.
Warum eine gemischte Tabelle den Typ verliert
Single-Table Design speichert jede Entity
in einer Tabelle hinter generischen Keys wie PK und SK. Das ist der ganze
Punkt — eine Query liefert Parent und Children zusammen. Aber es heißt, eine
Partition ist heterogen.
Nimm eine SaaS-Doc-Collaboration-App. Eine Workspace-Partition hält den Workspace-Record, seine Documents und die Comments auf diesen Documents:
| PK | SK | attributes |
|---|---|---|
| WS#acme | META | name, plan, seats |
| WS#acme | DOC#a1#META | title, owner, wordCount |
| WS#acme | DOC#a1#CMT#0007 | author, body, createdAt |
| WS#acme | DOC#a1#CMT#0008 | author, body, createdAt |
Query PK = "WS#acme" reicht alle vier Items in einem abgerechneten Read zurück.
Jetzt hat dein Code eine Liste roher Items und keinen zuverlässigen Weg zu sagen,
was ein Document und was ein Comment ist — außer String-Matching auf dem SK,
was brüchig wird, sobald sich dein Key-Format ändert.
Stempele den Type auf jedes Item
Der Fix ist ein Attribut auf jedem Write, das die Entity benennt:
| PK | SK | EntityType | title |
|---|---|---|---|
| WS#acme | META | Workspace | — |
| WS#acme | DOC#a1#META | Document | Q3 Roadmap |
| WS#acme | DOC#a1#CMT#0007 | Comment | — |
Branching auf item.EntityType === "Document" ist ein stabiler Equality-Check.
SK.startsWith("DOC#") && SK.includes("#CMT#") zu parsen ist eine Vermutung, die
bricht, wenn du den Key revisest. Der Type entkoppelt deine Read-Logik von deiner
Key-Encoding — das ist der echte Win.
Ein Read liefert drei Entity-Typen; das Type-Attribut routet jedes Item zum richtigen Handler, ohne die Keys anzufassen.
Einen GSI auf eine Entity verengen
Der Type verdient seinen Keep auf Indexes. Angenommen, du fügst einen GSI keyed
auf GSI1PK = WS#acme, GSI1SK = updatedAt hinzu, um „alles kürzlich Geänderte
in diesem Workspace, neueste zuerst“ zu listen. Ein überladener Index fegt
Documents und Comments ein — aber eine Feed-UI will vielleicht nur Documents.
Zwei Wege zu verengen, und der Unterschied ist Geld:
| Ansatz | Was es kostet | Wann nutzen |
|---|---|---|
FilterExpression auf Type | Liest alle matchenden Items, rechnet alle ab, droppt Non-Matches nach dem Read | Gemischte Entities sind im Result selten; schnell zu shippen |
Sparse Index (GSI1PK nur auf der Ziel-Entity geschrieben) | Nur die Entity, die du willst, landet je im Index | Eine Entity dominiert; du willst Zero Waste |
On-Demand in us-east-1 rechnet eine GSI-Query, die 100 gemischte Items à
2 KB zurückgibt, grob 100 RCU eventually-consistent — und eine
FilterExpression auf EntityType metert trotzdem jede Row, bevor sie die
Comments droppt. Ein Sparse Index, der Comments nie indexiert, rechnet nur die
Document-Rows. Modelliere beide Formen im
Pricing Calculator.
Eine FilterExpression läuft nachdem Items gelesen und Capacity verbraucht
wurden — AWS ist explizit, dass Filtering Read-Kosten nicht reduziert
(DynamoDB Developer Guide: FilterExpression).
Filtering auf Type ist ehrlich, nicht gratis: du zahlst für die Comments, die du
wegwirfst.
Um den Feed auf Documents zu verengen, trägt die Query eine Condition auf dem
Type-Attribut. Baue FilterExpression, Names und Values mit dem
DynamoDB Expression Builder — er emittiert
den #t = :doc-Placeholder, damit du kein Reserved Word vertippst.
KeyConditionExpression GSI1PK = :ws
FilterExpression #t = :doc
ExpressionAttributeNames { "#t": "EntityType" }
ExpressionAttributeValues { ":ws": "WS#acme", ":doc": "Document" }
Soll der Index nur Documents tragen und den Filter komplett skippen? Schreibe
GSI1PK nur auf Document-Items — ein .
Items ohne den GSI-Key replizieren nie in den Index, also berührt der Read nur
Documents. Das Type-Attribut sagt deinem Writer, welche Items qualifyen.
Halte den Wert stabil und singular
Wähle den Wert einmal und behandle ihn als Enum. Document, nie manchmal Doc
und manchmal document — ein driftender Wert ist schlimmer als keiner, weil
deine Equality-Checks bei einem Casing passen und das andere still missen.
Ein Type pro Item. Fühlt sich ein Item wie zwei Entities an, ist das meist ein Modeling-Smell — es sollten zwei Items sein, jedes in seiner eigenen Collection oder Sort-Key-Range, nicht eine Row mit zwei Hüten.
Der Migrations-Payoff
Der Grund, den Type zu stempeln, bevor du ihn brauchst: Re-Modeling. Der empfohlene Re-Model-Pfad ist Export, Transform, Reimport — und AWS dokumentiert Bulk-Export nach S3 genau für dieses Offline-Reshaping (Exporting DynamoDB to S3).
Wenn dieser Tag kommt, ist der Type die Spalte, nach der du GROUP BYst. Willst
du Comments in ihre eigene Tabelle heben oder den Export für ein Analytics-
Warehouse in Per-Entity-Files renormalisieren? Du splitest den Dump auf
EntityType. Ohne ihn reverse-engineerst du Keys über Millionen Rows.
Nächste Schritte
Ein Type-Attribut ist günstige Versicherung. Nutze es, um Entities in einem gemischten Read zu identifizieren, einen überladenen GSI zu filtern und sauber zu splitten, wenn du remodelst. Stempele es auf jeden Write ab Tag eins — nachzurüsten auf einer Live-Tabelle heißt Full Backfill.
Verwandte Lektüre: Single-Table Design für
das Mixed-Partition-Pattern, das es bedient, GSI vs LSI
für die Index-Form hinter einem Sparse Index, und
Query vs Scan dafür, warum eine
FilterExpression nie Read-Kosten spart.
Baue den Filter auf dem Type mit dem DynamoDB Expression Builder, und probier DynoTable, um eine echte Mixed-Entity-Tabelle zu browsen und die Type-Spalte über jedes Item ausgerichtet zu sehen.