dynamodb-toolbox-patterns

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

DynamoDB-Toolbox v2 Patterns (TypeScript)

DynamoDB-Toolbox v2 模式(TypeScript)

Overview

概述

This skill provides practical TypeScript patterns for using DynamoDB-Toolbox v2 with AWS SDK v3 DocumentClient. It focuses on type-safe schema modeling,
.build()
command usage, and production-ready single-table design.
本技能提供了在TypeScript中结合AWS SDK v3 DocumentClient使用DynamoDB-Toolbox v2的实用模式,重点关注类型安全的Schema建模、.build()命令的使用,以及可用于生产环境的单表设计。

When to Use

适用场景

  • Defining DynamoDB tables and entities with strict TypeScript inference
  • Modeling schemas with
    item
    ,
    string
    ,
    number
    ,
    list
    ,
    set
    ,
    map
    , and
    record
  • Implementing
    GetItem
    ,
    PutItem
    ,
    UpdateItem
    ,
    DeleteItem
    via
    .build()
  • Building query and scan access paths with primary keys and GSIs
  • Handling batch and transactional operations
  • Designing single-table systems with computed keys and entity patterns
  • 使用严格的TypeScript推断定义DynamoDB表和实体
  • 使用
    item
    string
    number
    list
    set
    map
    record
    建模Schema
  • 通过
    .build()
    实现
    GetItem
    PutItem
    UpdateItem
    DeleteItem
    操作
  • 基于主键和GSI构建查询和扫描访问路径
  • 处理批量和事务操作
  • 使用计算键和实体模式设计单表系统

Instructions

操作步骤

  1. Start from access patterns: identify read/write queries first, then design keys.
  2. Create table + entity boundaries: one table, multiple entities if using single-table design.
  3. Define schemas with constraints: apply
    .key()
    ,
    .required()
    ,
    .default()
    ,
    .transform()
    ,
    .link()
    .
  4. Use
    .build()
    commands everywhere
    : avoid ad-hoc command construction for consistency and type safety.
  5. Add query/index coverage: validate GSI/LSI paths for each required access pattern.
  6. Use batch/transactions intentionally: batch for throughput, transactions for atomicity.
  7. Keep items evolvable: use optional fields, defaults, and derived attributes for schema evolution.
  1. 从访问模式入手:先确定读写查询,再设计键。
  2. 创建表和实体边界:如果使用单表设计,一个表对应多个实体。
  3. 定义带约束的Schema:使用
    .key()
    .required()
    .default()
    .transform()
    .link()
  4. 全程使用.build()命令:为了一致性和类型安全,避免临时构造命令。
  5. 添加查询/索引覆盖:验证每个所需访问模式的GSI/LSI路径。
  6. 合理使用批量/事务:批量操作提升吞吐量,事务操作保证原子性。
  7. 保持项目可演进:使用可选字段、默认值和派生属性实现Schema演进。

Examples

示例

Install and Setup

安装与设置

bash
npm install dynamodb-toolbox @aws-sdk/client-dynamodb @aws-sdk/lib-dynamodb
typescript
import { DynamoDBClient } from '@aws-sdk/client-dynamodb';
import { DynamoDBDocumentClient } from '@aws-sdk/lib-dynamodb';
import { Table } from 'dynamodb-toolbox/table';
import { Entity } from 'dynamodb-toolbox/entity';
import { item, string, number, list, map } from 'dynamodb-toolbox/schema';

const client = new DynamoDBClient({ region: process.env.AWS_REGION ?? 'eu-west-1' });
const documentClient = DynamoDBDocumentClient.from(client);

export const AppTable = new Table({
  name: 'app-single-table',
  partitionKey: { name: 'PK', type: 'string' },
  sortKey: { name: 'SK', type: 'string' },
  indexes: {
    byType: { type: 'global', partitionKey: { name: 'GSI1PK', type: 'string' }, sortKey: { name: 'GSI1SK', type: 'string' } }
  },
  documentClient
});
bash
npm install dynamodb-toolbox @aws-sdk/client-dynamodb @aws-sdk/lib-dynamodb
typescript
import { DynamoDBClient } from '@aws-sdk/client-dynamodb';
import { DynamoDBDocumentClient } from '@aws-sdk/lib-dynamodb';
import { Table } from 'dynamodb-toolbox/table';
import { Entity } from 'dynamodb-toolbox/entity';
import { item, string, number, list, map } from 'dynamodb-toolbox/schema';

const client = new DynamoDBClient({ region: process.env.AWS_REGION ?? 'eu-west-1' });
const documentClient = DynamoDBDocumentClient.from(client);

export const AppTable = new Table({
  name: 'app-single-table',
  partitionKey: { name: 'PK', type: 'string' },
  sortKey: { name: 'SK', type: 'string' },
  indexes: {
    byType: { type: 'global', partitionKey: { name: 'GSI1PK', type: 'string' }, sortKey: { name: 'GSI1SK', type: 'string' } }
  },
  documentClient
});

Entity Schema with Modifiers and Complex Attributes

带修饰符和复杂属性的实体Schema

typescript
const now = () => new Date().toISOString();

export const UserEntity = new Entity({
  name: 'User',
  table: AppTable,
  schema: item({
    tenantId: string().required('always'),
    userId: string().required('always'),
    email: string().required('always').transform(input => input.toLowerCase()),
    role: string().enum('admin', 'member').default('member'),
    loginCount: number().default(0),
    tags: list(string()).default([]),
    profile: map({
      displayName: string().optional(),
      timezone: string().default('UTC')
    }).default({ timezone: 'UTC' })
  }),
  computeKey: ({ tenantId, userId }) => ({
    PK: `TENANT#${tenantId}`,
    SK: `USER#${userId}`,
    GSI1PK: `TENANT#${tenantId}#TYPE#USER`,
    GSI1SK: `EMAIL#${userId}`
  })
});
typescript
const now = () => new Date().toISOString();

export const UserEntity = new Entity({
  name: 'User',
  table: AppTable,
  schema: item({
    tenantId: string().required('always'),
    userId: string().required('always'),
    email: string().required('always').transform(input => input.toLowerCase()),
    role: string().enum('admin', 'member').default('member'),
    loginCount: number().default(0),
    tags: list(string()).default([]),
    profile: map({
      displayName: string().optional(),
      timezone: string().default('UTC')
    }).default({ timezone: 'UTC' })
  }),
  computeKey: ({ tenantId, userId }) => ({
    PK: `TENANT#${tenantId}`,
    SK: `USER#${userId}`,
    GSI1PK: `TENANT#${tenantId}#TYPE#USER`,
    GSI1SK: `EMAIL#${userId}`
  })
});

.build()
CRUD Commands

.build()
CRUD命令

typescript
import { PutItemCommand } from 'dynamodb-toolbox/entity/actions/put';
import { GetItemCommand } from 'dynamodb-toolbox/entity/actions/get';
import { UpdateItemCommand, $add } from 'dynamodb-toolbox/entity/actions/update';
import { DeleteItemCommand } from 'dynamodb-toolbox/entity/actions/delete';

await UserEntity.build(PutItemCommand)
  .item({ tenantId: 't1', userId: 'u1', email: 'A@Example.com' })
  .send();

const { Item } = await UserEntity.build(GetItemCommand)
  .key({ tenantId: 't1', userId: 'u1' })
  .send();

await UserEntity.build(UpdateItemCommand)
  .item({ tenantId: 't1', userId: 'u1', loginCount: $add(1) })
  .send();

await UserEntity.build(DeleteItemCommand)
  .key({ tenantId: 't1', userId: 'u1' })
  .send();
typescript
import { PutItemCommand } from 'dynamodb-toolbox/entity/actions/put';
import { GetItemCommand } from 'dynamodb-toolbox/entity/actions/get';
import { UpdateItemCommand, $add } from 'dynamodb-toolbox/entity/actions/update';
import { DeleteItemCommand } from 'dynamodb-toolbox/entity/actions/delete';

await UserEntity.build(PutItemCommand)
  .item({ tenantId: 't1', userId: 'u1', email: 'A@Example.com' })
  .send();

const { Item } = await UserEntity.build(GetItemCommand)
  .key({ tenantId: 't1', userId: 'u1' })
  .send();

await UserEntity.build(UpdateItemCommand)
  .item({ tenantId: 't1', userId: 'u1', loginCount: $add(1) })
  .send();

await UserEntity.build(DeleteItemCommand)
  .key({ tenantId: 't1', userId: 'u1' })
  .send();

Query and Scan Patterns

查询与扫描模式

typescript
import { QueryCommand } from 'dynamodb-toolbox/table/actions/query';
import { ScanCommand } from 'dynamodb-toolbox/table/actions/scan';

const byTenant = await AppTable.build(QueryCommand)
  .query({
    partition: `TENANT#t1`,
    range: { beginsWith: 'USER#' }
  })
  .send();

const byTypeIndex = await AppTable.build(QueryCommand)
  .query({
    index: 'byType',
    partition: 'TENANT#t1#TYPE#USER'
  })
  .options({ limit: 25 })
  .send();

const scanned = await AppTable.build(ScanCommand)
  .options({ limit: 100 })
  .send();
typescript
import { QueryCommand } from 'dynamodb-toolbox/table/actions/query';
import { ScanCommand } from 'dynamodb-toolbox/table/actions/scan';

const byTenant = await AppTable.build(QueryCommand)
  .query({
    partition: `TENANT#t1`,
    range: { beginsWith: 'USER#' }
  })
  .send();

const byTypeIndex = await AppTable.build(QueryCommand)
  .query({
    index: 'byType',
    partition: 'TENANT#t1#TYPE#USER'
  })
  .options({ limit: 25 })
  .send();

const scanned = await AppTable.build(ScanCommand)
  .options({ limit: 100 })
  .send();

Batch and Transaction Workflows

批量与事务工作流

typescript
import { BatchWriteCommand } from 'dynamodb-toolbox/table/actions/batchWrite';
import { TransactWriteCommand } from 'dynamodb-toolbox/table/actions/transactWrite';

await AppTable.build(BatchWriteCommand)
  .requests(
    UserEntity.build(PutItemCommand).item({ tenantId: 't1', userId: 'u2', email: 'u2@example.com' }),
    UserEntity.build(PutItemCommand).item({ tenantId: 't1', userId: 'u3', email: 'u3@example.com' })
  )
  .send();

await AppTable.build(TransactWriteCommand)
  .requests(
    UserEntity.build(PutItemCommand).item({ tenantId: 't1', userId: 'u4', email: 'u4@example.com' }),
    UserEntity.build(UpdateItemCommand).item({ tenantId: 't1', userId: 'u1', loginCount: $add(1) })
  )
  .send();
typescript
import { BatchWriteCommand } from 'dynamodb-toolbox/table/actions/batchWrite';
import { TransactWriteCommand } from 'dynamodb-toolbox/table/actions/transactWrite';

await AppTable.build(BatchWriteCommand)
  .requests(
    UserEntity.build(PutItemCommand).item({ tenantId: 't1', userId: 'u2', email: 'u2@example.com' }),
    UserEntity.build(PutItemCommand).item({ tenantId: 't1', userId: 'u3', email: 'u3@example.com' })
  )
  .send();

await AppTable.build(TransactWriteCommand)
  .requests(
    UserEntity.build(PutItemCommand).item({ tenantId: 't1', userId: 'u4', email: 'u4@example.com' }),
    UserEntity.build(UpdateItemCommand).item({ tenantId: 't1', userId: 'u1', loginCount: $add(1) })
  )
  .send();

Single-Table Design Guidance

单表设计指南

  • Model each business concept as an entity with strict schema.
  • Keep PK/SK predictable and composable (
    TENANT#
    ,
    USER#
    ,
    ORDER#
    ).
  • Encode access paths into GSI keys, not in-memory filters.
  • Prefer append-only timelines for audit/history data.
  • Keep hot partitions under control with scoped partitions and sharding where needed.
  • 将每个业务概念建模为带有严格Schema的实体。
  • 保持PK/SK可预测且可组合(如
    TENANT#
    USER#
    ORDER#
    )。
  • 将访问路径编码到GSI键中,而非内存过滤器。
  • 对于审计/历史数据,优先使用追加式时间线。
  • 通过范围分区和分片(如有需要)控制热分区。

Best Practices

最佳实践

  • Design keys from access patterns first, then derive entity attributes.
  • Keep one source of truth for key composition (
    computeKey
    ) to avoid drift.
  • Use
    .options({ consistent: true })
    only where strict read-after-write is required.
  • Prefer targeted queries over scans for runtime request paths.
  • Add conditional expressions for idempotency and optimistic concurrency control.
  • Validate batch/transaction size limits before execution to avoid partial failures.
  • 先从访问模式设计键,再推导实体属性。
  • 保持键组合的单一可信来源(
    computeKey
    ),避免不一致。
  • 仅在需要严格的写后读一致性时使用
    .options({ consistent: true })
  • 对于运行时请求路径,优先使用定向查询而非扫描。
  • 添加条件表达式以实现幂等性和乐观并发控制。
  • 在执行前验证批量/事务大小限制,避免部分失败。

Constraints and Warnings

约束与警告

  • DynamoDB-Toolbox v2 relies on AWS SDK v3 DocumentClient integration.
  • Avoid table scans in request paths unless explicitly bounded.
  • Use conditional writes for concurrency-sensitive updates.
  • Transactions are limited and slower than single-item writes; use only for true atomic requirements.
  • Validate key design against target throughput before implementation.
  • DynamoDB-Toolbox v2依赖于AWS SDK v3 DocumentClient的集成。
  • 除非明确限制范围,否则避免在请求路径中使用表扫描。
  • 对并发敏感的更新使用条件写入。
  • 事务有数量限制且比单条写入慢;仅在真正需要原子性时使用。
  • 在实现前验证键设计是否符合目标吞吐量。

References

参考资料

Primary references curated from Context7 are available in:
  • references/api-dynamodb-toolbox-v2.md
由Context7整理的主要参考资料位于:
  • references/api-dynamodb-toolbox-v2.md