如何将 DynamoDB 表导出为 CSV(4 种方法)
DynamoDB 没有原生的"导出为 CSV"按钮。每个值返回时都包裹在
DynamoDB 的整理后 JSON中——{"S": "..."}、
{"N": "123"}、{"M": {...}}——而一张表可以容纳嵌套的映射、列表和
集合,没有明显的扁平列表示。所以"把 DynamoDB 导出为 CSV"
其实是两个问题:把项取出来,然后把带类型的 JSON 扁平化成
行。控制台和托管导出都不会为你做第二步。
本指南按表大小和你的项携带多少嵌套,对四种方法 排序。
如何将 DynamoDB 表导出为 CSV?
DynamoDB 没有原生的 CSV 导出功能,因此你需要扫描或快照表,再将其带类型的 JSON 扁平化为行。小表可使用 AWS CLI scan + jq 或短脚本;大表可导出到 S3 后转换;如需过滤且开箱即用的 CSV,可使用 DynoTable 等 GUI 工具。
- 小表、临时: AWS CLI
scan+jq,或一段 20 行的脚本 (方法 1 / 方法 3)。 在嵌套属性出现之前都没问题。 - 大表(数 GB+): DynamoDB 导出到 S3 (方法 2),然后转换导出文件。 它异步运行且不消耗读容量——但它输出 DynamoDB JSON,而非 CSV。
- 过滤 / 整形后的 CSV(列的子集,仅部分项): GUI 导出或 脚本。托管的 S3 导出给你的是整张表,不带过滤。
方法 1:AWS CLI scan + jq
对于小表,你可以扫描它并用 jq 重塑输出。Scan 会读取
表中的每个项,并以最多 1 MB 的页返回;CLI 会
自动为你处理分页
(AWS 文档:扫描表)。
aws dynamodb scan --table-name MyTable --output json \
| jq -r '.Items[] | [.id.S, .name.S, .price.N] | @csv' \
> out.csv陷阱在那条 jq 行里:你必须手写 .id.S、.name.S、
.price.N——越过每个属性的类型描述符(S、N、B、
BOOL、M、L、SS、NS、BS)去取原始值。对于
带三个字符串列的扁平表,这还可控。一旦你有了以下情况它就崩溃:
- 嵌套映射/列表——
{"M": {...}}或{"L": [...]}没有单一列可 扁平化进去;@csv卡壳,或者你得手动把单元格 JSON 编码。 - 集合——
{"SS": ["a","b"]}是数组,不是标量。 - 稀疏属性——DynamoDB 无 schema,所以项 A 可能有
price,而 项 B 可能没有。你固定的列列表会静默丢列或错位。
也没有理解 DynamoDB 类型的 --output csv。CLI 的 csv
输出会把原始响应连同描述符一起扁平化——所以你仍然需要 jq(或
脚本)来剥离类型标签。这正是"通过 AWS CLI 把 DynamoDB 表导出为
CSV"在最简单情况之外永远不是一行命令的核心原因。
要用这种方式导出一张较大的整表而又不耗一整天,用
--segment / --total-segments 并行化扫描
(AWS 文档:并行扫描——
DynamoDB "通过对每个项的分区键应用哈希函数来把项分配到段",
所以段可能不均匀),并读
分页,这样你就不会停在第一个 1 MB 页。
方法 2:DynamoDB 导出到 S3(大表)
对于任何有实际规模的表,托管的导出到 Amazon S3 是正确的工具。 它从你的时间点恢复(PITR)窗口内的任意时间点导出快照—— 所以必须先在表上启用 PITR——它异步运行, 并不消耗读容量单位,因此对你表的吞吐量或可用性零影响 (AWS 文档: "导出是异步的,它们不消耗读容量单位(RCU),对表性能和可用性无 影响";"要使用导出功能,你需要在表上启用 PITR")。这也是控制台的导出到 S3 操作在底层触发的:控制台只是同一个 API 的前端, 所以它带有同样的 PITR 要求和同样的 JSON 输出。
aws dynamodb export-table-to-point-in-time \
--table-arn arn:aws:dynamodb:us-east-1:123456789012:table/MyTable \
--s3-bucket my-export-bucket \
--export-format DYNAMODB_JSON唯一的坑:S3 导出不输出 CSV。 它只写 DynamoDB JSON
或 Amazon Ion,作为 gzip 压缩的文件,采用
JSON-lines 格式(每行一个项),外加清单
文件(AWS 文档:导出输出格式——
数据文件以 .json.gz 写出,"格式是 JSON lines",旁边还有
manifest-summary.json / manifest-files.json)。之后你仍需要一个转换步骤:
- Athena / Glue 能直接读取导出的 DynamoDB JSON——把一张表指向该
S3 前缀,然后从一个
SELECT写出 CSV(这是常见的"把 DynamoDB 导出到 S3 再到 CSV"管道)。AWS 指出"许多 AWS 服务,例如 Athena 和 AWS Glue,会自动解析这种格式" (导出输出格式)。 - 自己动手——解压
.gz文件,解析每个 JSON 行,并把 它扁平化(与其他每种方法相同的扁平化问题)。
它也是整表快照:没有服务端过滤器来只导出 部分项。如果你需要子集,要么之后在 Athena 中过滤,要么 改用脚本 / GUI。
方法 3:一段快速脚本(boto3 / Node)
当你需要一份整形过的 CSV——特定的列、过滤后的子集、对嵌套
字段的自定义处理——一段小脚本胜过与 jq 搏斗。其优势在于 AWS SDK
为你反整理带类型的 JSON:boto3 的资源接口和 JS SDK 的
DynamoDBDocumentClient 返回普通的 {"price": 2000} 而非
{"price": {"N": "2000"}}(boto3 的资源接口让"数据类型
隐式化",依据
AWS Python 指南;
JS DocumentClient "把带注解的响应数据转换为原生 JavaScript 类型",
依据 @aws-sdk/lib-dynamodb)。
import boto3, csv
table = boto3.resource("dynamodb").Table("MyTable")
rows, resp = [], table.scan()
rows += resp["Items"]
while "LastEvaluatedKey" in resp: # 分页到结尾
resp = table.scan(ExclusiveStartKey=resp["LastEvaluatedKey"])
rows += resp["Items"]
with open("out.csv", "w", newline="") as f:
w = csv.DictWriter(f, fieldnames=["id", "name", "price"])
w.writeheader()
for r in rows:
w.writerow({k: r.get(k) for k in w.fieldnames})你仍然要自己负责 SDK 替你做不了的两个决定:如何把嵌套的
映射/列表扁平化成列(把单元格 JSON 编码?把键做点路径?),以及如何处理
稀疏属性(这里缺失的键会通过 r.get(k) 变成空单元格)。
而且别丢掉 LastEvaluatedKey 循环——单次 scan() 调用只返回
第一个 1 MB 页,所以没有它你会静默地只导出表的一部分。
与方法 1 相同的告诫:这里的整表 scan 仍会消耗读容量并
与实时流量竞争。对于大表,优先用
方法 2并重塑导出文件。
方法 4:在 DynoTable 中一键导出
脚本和 CLI 路线可行,但你每次都要重建同样的扁平化和分页 逻辑。DynoTable 为你完成它:运行或过滤一个查询, 然后把可见的行直接导出为 CSV(或 Excel)——类型描述符 被解包、嵌套的映射和列表被扁平化、集合被处理,且输出中 只有你真正想要的项和列。
因为你导出的是当前视图,你得到的是 方法 2的整表快照无法 给你的那份过滤/整形 CSV——而无需写扫描循环。它是一款桌面 DynamoDB 客户端,正是你已经用来浏览表的同一个工具;看看它与其他 DynamoDB GUI 的对比。
坑:DynamoDB JSON 与扁平 CSV
无论你选哪种方法,DynamoDB 数据模型与扁平 CSV 之间的 同一批不匹配都会咬你:
- 类型描述符。 原始 API / CLI / S3 导出的输出会包裹每个值
(
{"S": "..."}、{"N": "123"})。你要么通过 SDK 解包它,要么自己剥离 描述符。完整集合是S、N、B、BOOL、NULL、M、L、SS、NS、BS——参见 DynamoDB 数据类型。 - 嵌套映射和列表(
M、L)可嵌套深达 32 层 (AWS 文档:数据类型—— 列表和映射"可以相互嵌套,以表示复杂的数据结构 深达 32 层"),且没有自然的单列形式。请提前决定: 把单元格 JSON 编码,或把嵌套键展开成点路径列(address.city)。 - 集合(
SS/NS/BS)是无序集合,不是标量——AWS 警告 "集合内值的顺序不会被保留" (数据类型)—— 所以扁平化成一个有分隔符的字符串,且不要依赖元素顺序。 - 稀疏属性。 DynamoDB 无 schema,所以两个项可以有不同的 属性。没有固定的列集;把所有项的键取并集,否则 列会错位。这是 单表设计的直接后果,在那里一张表容纳了多种 实体形状。
- 分页。
Scan(和Query)每次调用最多返回 1 MB。如果你不 在LastEvaluatedKey上循环,你会静默地只导出第一页。参见 分页。 - 数字精度。 DynamoDB 数字携带多达 38 位精度,并 以字符串传输(AWS 文档:数据类型: "数字最多可有 38 位精度";"所有数字都以字符串形式通过 网络发送到 DynamoDB");电子表格软件可能把长数字或 ID 强制转成浮点数并丢失位数。请把它们保留为文本。
常见问题
如何用 AWS CLI 把 DynamoDB 表导出为 CSV?
扫描表并用 jq 重塑输出(方法 1):aws dynamodb scan →
jq 剥离每个值的类型描述符 → @csv。没有 DynamoDB 感知的
--output csv,所以你总要自己做类型剥离,且它在嵌套
映射、列表和集合上会失败。
我能直接从 AWS 把 DynamoDB 表导出为 CSV 吗?
不能一步到位。控制台和托管的 S3 导出都产出 DynamoDB JSON 或
Amazon Ion,从不产出 CSV。你总需要一个转换步骤——CLI + jq、脚本、
对 S3 导出文件的 Athena/Glue,或一个为你做扁平化的 GUI。
如何在不影响生产的情况下导出整张 DynamoDB 表?
使用导出到 S3 功能(方法 2)。它异步运行且消耗
零读容量单位,所以它不与实时流量竞争——不像
Scan 那样针对你表的吞吐量计量
(AWS 文档)。
它要求启用 PITR,并导出整张表,而非过滤后的子集。
如何把 DynamoDB 导出到 S3 为 CSV?
托管导出只把 DynamoDB JSON / Ion 写到 S3,所以"到 CSV"是第二
跳:把导出前缀注册为一个 Athena(或 Glue)表,并从一个
SELECT 写出 CSV。没有 --export-format CSV。
如何把 DynamoDB 导出到 Excel?
先导出为 CSV(上面的任意方法),然后在 Excel 中打开 CSV——把长
数字 ID 保留为文本,这样它们不会被强制转成浮点数。没有
从 DynamoDB 直接导出 .xlsx;像 DynoTable 这样的 GUI 能把当前视图
直接保存为可供电子表格使用的 CSV。
为什么我导出的 JSON 到处都是 {"S": ...} 和 {"N": ...}?
那是 DynamoDB 整理后的线缆格式——每个值都用一个类型
描述符标记。在写 CSV 之前,用 SDK、
DynamoDB JSON 转换器或一个 GUI 反整理它。
无论数据来自 API、CLI 还是 S3 导出,线缆格式都一样。
用 DynoTable 浏览、过滤并把你自己的表导出为 CSV,或先在 JSON 转换器中解包一个 DynamoDB JSON 样本。