mcpField
D
dynamodb-toolbox-patterns

dynamodb-toolbox-patterns

github.com/giuseppe-trisciuoglio数据与数据库3653.5k 次安装7 周前更新
代码仓库

关于 dynamodb-toolbox-patterns

为使用 AWS SDK v3 DocumentClient 的开发者提供 DynamoDB-Toolbox v2 的 TypeScript 模式,涵盖类型安全的 Schema、命令构建和单表访问设计。

主要功能

  1. 01类型安全的 Schema 建模
  2. 02使用 `.build()` 构建 CRUD 命令
  3. 03查询与扫描访问路径
  4. 04批处理与事务模式
  5. 05单表设计指导

适用场景

  1. 01定义 DynamoDB 实体与 Schema
  2. 02实现类型化 CRUD 操作
  3. 03设计键与 GSI 访问路径
  4. 04选择批处理或事务写入

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/giuseppe-trisciuoglio/developer-kit --skill dynamodb-toolbox-patterns

安装后在 Claude Code 中输入/dynamodb-toolbox-patterns确认已加载。

附带文件references/api-dynamodb-toolbox-v2.md

详细介绍

DynamoDB-Toolbox v2 模式(TypeScript)

概述

本技能提供使用 DynamoDB-Toolbox v2 和 AWS SDK v3 DocumentClient 的实用 TypeScript 模式。重点介绍类型安全的架构建模、.build() 命令用法,以及适用于生产环境的单表设计。

适用场景

  • 使用严格的 TypeScript 类型推断定义 DynamoDB 表和实体
  • 使用 item、string、number、list、set、map 和 record 建模架构
  • 通过 .build() 实现 GetItem、PutItem、UpdateItem、DeleteItem
  • 使用主键和 GSI 构建查询和扫描访问路径
  • 处理批量和事务操作
  • 使用计算键和实体模式设计单表系统

说明

  1. 从访问模式入手:先识别读写查询,再设计键。
  2. 划分表和实体边界:采用单表设计时,使用一张表、多个实体。
  3. 定义带约束的架构:应用 .key()、.required()、.default()、.transform()、.link()。
  4. 所有命令都使用 .build():避免临时构造命令,以确保一致性和类型安全。
  5. 覆盖查询和索引路径:针对每种必需的访问模式验证 GSI/LSI 路径。
  6. 有目的地使用批量操作和事务:批量操作用于提高吞吐量,事务用于保证原子性。
  7. 确保项目可演进:使用可选字段、默认值和派生属性来支持架构演进。

示例

安装和设置
npm install dynamodb-toolbox @aws-sdk/client-dynamodb @aws-sdk/lib-dynamodb
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
});
带修饰符和复杂属性的实体架构
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 命令
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: '[email protected]' })
  .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();
查询和扫描模式
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();
批量和事务工作流
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: '[email protected]' }),
    UserEntity.build(PutItemCommand).item({ tenantId: 't1', userId: 'u3', email: '[email protected]' })
  )
  .send();

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

单表设计指南

  • 将每个业务概念建模为具有严格架构的实体。
  • 保持 PK/SK 可预测且可组合(TENANT#、USER#、ORDER#)。
  • 将访问路径编码到 GSI 键中,而不是使用内存过滤器。
  • 审计和历史数据优先采用仅追加时间线。
  • 通过限定分区,并在需要时进行分片,控制热点分区。

最佳实践

  • 先根据访问模式设计键,再推导实体属性。
  • 使用单一事实来源来组合键(computeKey),避免定义不一致。
  • 仅在严格要求写后读一致性的场景使用 .options({ consistent: true })。
  • 运行时请求路径优先使用定向查询,而不是扫描。
  • 添加条件表达式,实现幂等性和乐观并发控制。
  • 执行前验证批量操作和事务的大小限制,避免部分失败。

限制和警告

  • DynamoDB-Toolbox v2 依赖与 AWS SDK v3 DocumentClient 集成。
  • 除非明确限定扫描范围,否则避免在请求路径中扫描表。
  • 对并发敏感的更新使用条件写入。
  • 事务有数量限制,且比单项目写入慢;仅在确实需要原子性的场景使用。
  • 实施前根据目标吞吐量验证键设计。

参考资料

从 Context7 精选的主要参考资料位于:

  • references/api-dynamodb-toolbox-v2.md

评论

支持 Markdown