You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

不使用Scan在DynamoDB中按两个条件查询数据的实现方案

实现方案

DynamoDB的Query原生不支持跨不同属性的OR条件查询,要避免Scan操作,你可以通过两次独立Query+结果去重的方式实现需求,全程不会触发全表扫描。

前置准备

你已经有了isValue作为分区键的GSI,还需要新增一个GSI支持按xdate范围查询:

  • 新增GSI的分区键:可以设置一个所有记录都共用的固定值字段(比如所有记录新增recordType字段,值固定为default)作为该GSI的分区键
  • 新增GSI的排序键:设置为xdate

核心逻辑

拆成两个互不干扰的Query查询,再合并结果去重:

  1. 第一次查询:使用已有的isValue GSI,查询分区键值为TRUE的所有记录,得到所有满足isValue == true的数据集
  2. 第二次查询:使用新建的xdate GSI,查询分区键为固定值、排序键xdate < 今日ISO格式日期的所有记录,得到所有满足xdate条件的数据集
  3. 合并两个数据集,按表主键(ID + SID)去重,避免同时满足两个条件的记录重复返回

TypeScript 代码示例(基于AWS SDK v3)

首先安装依赖:

npm install @aws-sdk/client-dynamodb @aws-sdk/lib-dynamodb

代码实现:

import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
import { DynamoDBDocumentClient, QueryCommand } from "@aws-sdk/lib-dynamodb";

// 初始化客户端
const client = new DynamoDBClient({ region: "你的AWS区域" });
const docClient = DynamoDBDocumentClient.from(client);
const TABLE_NAME = "你的表名";
const XDATE_GSI_NAME = "你新建的xdate GSI名称";
const IS_VALUE_GSI_NAME = "已有的isValue GSI名称";

// 生成今日的ISO日期字符串,和表中存储格式保持一致
const todayIso = new Date().toISOString();

async function queryTargetData() {
  // 第一次查询:所有isValue == true的记录
  const isValueQuery = new QueryCommand({
    TableName: TABLE_NAME,
    IndexName: IS_VALUE_GSI_NAME,
    KeyConditionExpression: "isValue = :val",
    ExpressionAttributeValues: {
      ":val": true
    }
  });
  const isValueRes = await docClient.send(isValueQuery);
  const isValueItems = isValueRes.Items || [];

  // 第二次查询:所有xdate < 今日的记录
  const xdateQuery = new QueryCommand({
    TableName: TABLE_NAME,
    IndexName: XDATE_GSI_NAME,
    KeyConditionExpression: "recordType = :type AND xdate < :today",
    ExpressionAttributeValues: {
      ":type": "default",
      ":today": todayIso
    }
  });
  const xdateRes = await docClient.send(xdateQuery);
  const xdateItems = xdateRes.Items || [];

  // 合并去重,按主键ID+SID作为唯一标识
  const itemMap = new Map();
  [...isValueItems, ...xdateItems].forEach(item => {
    const key = `${item.ID}#${item.SID}`;
    if (!itemMap.has(key)) {
      itemMap.set(key, item);
    }
  });

  return Array.from(itemMap.values());
}

// 调用示例
queryTargetData().then(console.log).catch(console.error);

注意事项

  • 如果单次查询返回数据量超过1MB,需要判断返回结果中的LastEvaluatedKey,循环分页查询完所有符合条件的记录再合并
  • 如果单表数据量超过10GB,固定值作为分区键的GSI可能出现热分区问题,可以将固定值拆分为多个分片(比如default#1、default#2...共10个),写入时随机分配分片值,查询时并行查询所有分片的结果再合并即可解决
  • 必须保证xdate存储的是ISO8601格式的字符串,才能保证字符串比较的结果和日期先后顺序一致

内容的提问来源于stack exchange,提问作者user2427573

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 11:06:04