【问题标题】:Getting "key schema too big" error with LocalSecondaryIndexes wth DynamoDB?使用 DynamoDB 的 LocalSecondaryIndexes 出现“键架构太大”错误?
【发布时间】:2025-12-20 02:00:06
【问题描述】:

我正在尝试使用如下所示的 Node.js 脚本创建一个 DynamoDB 表。如果我删除 LocalSecondaryIndexes 块并删除删除后不再需要的两个属性定义,则代码可以正常工作并成功创建表。但是使用下面代码中显示的那个块,我从 DynamoDB 得到以下错误:

Unable to create table. Error JSON: {
  "message": "Key Schema too big.  Key Schema must at most consist of the hash and range key of a table",
  "code": "ValidationException",
  "time": "2019-02-13T19:45:34.482Z",
  "statusCode": 400,
  "retryable": false,
  "retryDelay": 29.475438988642534
}

我该如何解决这个问题?

代码如下:

// Create the quizzes table in DynamoDB.
var AWS = require('aws-sdk');

AWS.config.update({
  region: process.env.AWS_REGION,
  endpoint: process.env.AWS_ENDPOINT
});

var dynamodb = new AWS.DynamoDB();

var params = {
    TableName : "Quizzes",
    KeySchema: [
        { AttributeName: "author_id", KeyType: "HASH"},  //Partition key
        { AttributeName: "quiz_id", KeyType: "RANGE" }  //Sort key
    ],
    // Secondary key allows us to get all the different versions of a
    //  a particular quiz, referenced by quiz name, for all the available
    //  languages the quiz supports.
    LocalSecondaryIndexes: [
        {
            IndexName: "ForeignLanguageSupportIndex",
            KeySchema: [
                { AttributeName: "author_id", KeyType: "HASH"},  //Partition key
                { AttributeName: "quiz_name", KeyType: "RANGE" },  //Sort key
                { AttributeName: "language_code", KeyType: "RANGE" },  //Sort key
                { AttributeName: "quiz_id", KeyType: "RANGE" }  //Sort key
            ],
            Projection: {
                ProjectionType: "ALL"
            }
        }
    ],
    AttributeDefinitions: [
        { AttributeName: "author_id", AttributeType: "S" },
        { AttributeName: "quiz_name", AttributeType: "S" },
        { AttributeName: "language_code", AttributeType: "S" },
        { AttributeName: "quiz_id", AttributeType: "S" }
    ],
    // Using on-demand provisioning (pay as you go, no pre-allocation).
    BillingMode: "PAY_PER_REQUEST"
};

dynamodb.createTable(params, function(err, data) {
    if (err) {
        console.error("Unable to create table. Error JSON:", JSON.stringify(err, null, 2));
    } else {
        console.log("Created table. Table description JSON:", JSON.stringify(data, null, 2));
    }
});

【问题讨论】:

    标签: javascript node.js indexing amazon-dynamodb


    【解决方案1】:

    每个表/索引必须有 1 个哈希键和 0 或 1 个范围键。如果您需要使用多个属性进行查询,您可以创建多个索引,或者,如果数据是分层的,您可以将多条数据组合到您的排序键中。 (官方示例见AWS blog post。另见Best Practices for Using Sort Keys to Organize Data。)

    如何创建表格?

    你可以像这样创建你需要的索引:

    // Create the quizzes table in DynamoDB.
    var AWS = require('aws-sdk');
    
    AWS.config.update({
      region: process.env.AWS_REGION,
      endpoint: process.env.AWS_ENDPOINT
    });
    
    var dynamodb = new AWS.DynamoDB();
    
    var params = {
        TableName : "Quizzes",
        KeySchema: [
            { AttributeName: "author_id", KeyType: "HASH"},  //Partition key
            { AttributeName: "quiz_id", KeyType: "RANGE" }  //Sort key
        ],
        // Secondary key allows us to get all the different versions of a
        //  a particular quiz, referenced by quiz name, for all the available
        //  languages the quiz supports.
        LocalSecondaryIndexes: [
            {
                IndexName: "ForeignLanguageSupportIndex",
                KeySchema: [
                    { AttributeName: "author_id", KeyType: "HASH"},  //Partition key
                    { AttributeName: "quiz_name_language", KeyType: "RANGE" },  //Sort key
    
                ],
                Projection: {
                    ProjectionType: "ALL"
                }
            }
        ],
        AttributeDefinitions: [
            { AttributeName: "author_id", AttributeType: "S" },
            { AttributeName: "quiz_name_language", AttributeType: "S" },
            { AttributeName: "quiz_id", AttributeType: "S" }
        ],
        // Using on-demand provisioning (pay as you go, no pre-allocation).
        BillingMode: "PAY_PER_REQUEST"
    };
    
    dynamodb.createTable(params, function(err, data) {
        if (err) {
            console.error("Unable to create table. Error JSON:", JSON.stringify(err, null, 2));
        } else {
            console.log("Created table. Table description JSON:", JSON.stringify(data, null, 2));
        }
    });
    

    那么我的数据是什么样的?

    您读/写的对象看起来像这样:

    {
        author_id: "author1234",
        quiz_name: "DynamoDBExperienceSurvey",
        language_code: "en-us",
        quiz_name_language: "DynamoDBExperienceSurvey/en-us",
        quiz_id: "55dc0736-2fdf-11e9-b210-d663bd873d93",
        quiz_data: {
            ...
        }
    }
    

    如何执行查询?

    这里是key condition expressions 以获得您需要的数据。

    要获取某个作者的所有调查,您可以仅使用哈希键查询您的表或 LSI。

    author_id = "theAuthorId" 
    

    要根据名称获取测验的所有语言变体,您的关键条件是

    author_id = "theAuthorId" AND begins_with(quiz_name_language, "theQuizName/")
    

    在这种情况下,请务必在测验名称的末尾包含 /(或您使用的任何分隔符),否则“theQuizName”也会返回“theQuizName2”、“theQuizName3”等的结果.

    奖励:您还可以使用语言代码的第一部分查询特定语言的所有区域化变体。

    author_id = "theAuthorId" AND begins_with(quiz_name_language, "theQuizName/en-")
    

    【讨论】:

      【解决方案2】:

      每个表、本地二级索引 (LSI) 或全局二级索引 (GSI) 只能有 1 个哈希键和 1 个排序键。

      您要么需要将 quiz_name、language_code 和 quiz_id 连接成一个字符串,要么创建多个 LSI。

      选择取决于您需要如何查询 LSI。

      【讨论】:

      • 我在构建代码时使用了本指南:dynamodbguide.com/local-secondary-indexes。该示例具有用于主 KeySchema 的哈希键/排序键,以及用于 LSI 的哈希键/排序键。还是我不理解术语?我想要直接访问唯一测验的主键,但需要二级索引,这样我就可以找出特定“author_id/quiz_name/language_code”三元组的所有可用测验。换句话说,给定由特定用户编写的唯一测验名称,扫描所有可用不同语言版本的测验。
      • 您需要在数据模型中创建一个属性,该属性是包含您的元组的单个字符串。 IE。创建一个新属性,其中数据如下所示:“author12335/mycoolquiz/en-us”。您可以使用begins_with 操作来查询特定作​​者或作者/测验。
      • @MatthewPope 我明白你在说什么,但不知道如何编码。您能否使用显示表定义的 Javascript 代码 sn-p 将您的评论提升为答案?
      最近更新 更多