У меня есть таблица DynamoDB, созданная с помощью следующего кода:
const params = {
TableName,
AttributeDefinitions: [{
AttributeName: 'post_id',
AttributeType: 'S'
}, {
AttributeName: 'parent_post_id',
AttributeType: 'S'
}, {
AttributeName: 'created_at',
AttributeType: 'S'
}, {
AttributeName: 'average_rating',
AttributeType: 'N'
}],
KeySchema: [{
AttributeName: 'post_id',
KeyType: 'HASH'
}, {
AttributeName: 'created_at',
KeyType: 'RANGE'
}],
GlobalSecondaryIndexes: [{
IndexName: 'parent_post_id-created_at-index',
ProvisionedThroughput: {
ReadCapacityUnits: 5,
WriteCapacityUnits: 5
},
KeySchema: [{
AttributeName: 'parent_post_id',
KeyType: 'HASH'
}, {
AttributeName: 'created_at',
KeyType: 'SORT'
}],
Projection: {
ProjectionType: 'ALL'
}
}, {
IndexName: 'parent_post_id-averge_rating-index',
ProvisionedThroughput: {
ReadCapacityUnits: 5,
WriteCapacityUnits: 5
},
KeySchema: [{
AttributeName: 'parent_post_id',
KeyType: 'HASH'
}, {
AttributeName: 'average_rating',
KeyType: 'SORT'
}],
Projection: {
ProjectionType: 'ALL'
}
}],
ProvisionedThroughput: {
ReadCapacityUnits: 1,
WriteCapacityUnits: 1
}
};
Затем я пытаюсь выполнить запрос с разбивкой на страницы:
const paramsPosts = {
TableName: this.table,
IndexName: 'parent_post_id-created_at-index',
KeyConditionExpression: '#parent_post_id = :parent_post_id',
FilterExpression: '#resource_id = :resource_id',
ExpressionAttributeNames: {
'#parent_post_id': 'parent_post_id',
'#resource_id': 'resource_id',
},
ExpressionAttributeValues: {
':parent_post_id': '-',
':resource_id': resource_id,
},
Limit: limit,
ScanIndexForward: true,
ExclusiveStartKey: lastEvaluatedKey
};
Когда я отправляю запрос с этими значениями, все работает:
{
"resource_id": "VALID_RESOURCE_ID",
"limit": 5
}
Получил следующий результат:
{
"data": {
"posts": {
"items": [
{
"comment": "This comment 1.",
"created_at": "2018-07-31T19:40:21.899Z"
},
{
"comment": "This comment 2.",
"created_at": "2018-07-31T19:40:26.460Z"
},
{
"comment": "This comment 3.",
"created_at": "2018-07-31T19:40:30.810Z"
},
{
"comment": "This comment 4.",
"created_at": "2018-07-31T19:40:35.057Z"
},
{
"comment": "This comment 5.",
"created_at": "2018-07-31T19:40:39.341Z"
}
],
"summary": {
"total_count": 13
},
"paging": {
"next": {
"post_id": "660b4878-e883-41ce-af4e-c393a20aac08",
"created_at": "2018-07-31T19:40:39.341Z",
"parent_post_id": "-"
},
"prev": null
}
}
}
}
Здесь data.posts.paging.next - это LastEvaluatedKey, который возвращает DynamoDB, и когда я пытаюсь использовать это значение для разбивки на страницы, я получил следующую ошибку:
{
"data": {
"posts": null
},
"errors": [
{
"message": "The request processing has failed because of an unknown error, exception or failure.",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"posts"
],
"extensions": {
"code": "INTERNAL_SERVER_ERROR",
"exception": {
"message": "The request processing has failed because of an unknown error, exception or failure.",
"code": "InternalFailure",
"time": "2018-07-31T21:16:56.008Z",
"requestId": "10dc5a07-a18e-407b-bba3-ad57506d5fd2",
"statusCode": 500,
"retryable": true,
"stacktrace": [
"InternalFailure: The request processing has failed because of an unknown error, exception or failure.",
" at Request.extractError (/home/node/node_modules/aws-sdk/lib/protocol/json.js:48:27)",
" at Request.callListeners (/home/node/node_modules/aws-sdk/lib/sequential_executor.js:105:20)",
" at Request.emit (/home/node/node_modules/aws-sdk/lib/sequential_executor.js:77:10)",
" at Request.emit (/home/node/node_modules/aws-sdk/lib/request.js:683:14)",
" at Request.transition (/home/node/node_modules/aws-sdk/lib/request.js:22:10)",
" at AcceptorStateMachine.runTo (/home/node/node_modules/aws-sdk/lib/state_machine.js:14:12)",
" at /home/node/node_modules/aws-sdk/lib/state_machine.js:26:10",
" at Request.<anonymous> (/home/node/node_modules/aws-sdk/lib/request.js:38:9)",
" at Request.<anonymous> (/home/node/node_modules/aws-sdk/lib/request.js:685:12)",
" at Request.callListeners (/home/node/node_modules/aws-sdk/lib/sequential_executor.js:115:18)"
]
}
}
}
]
}
У меня DynamoDB работает локально внутри контейнера Docker с флагом InMemory, установленным в значение true.
Я думал, что мне нужно отправить только GSI Key, который состоит из parent_post_id (ключ раздела) и created_at (ключ сортировки), но, читая в некоторых местах, я обнаружил, что мне также нужно отправить ключ таблицы. Если я удалю post_id, который является только частью ключа таблицы, я получу следующую ошибку:
{
"data": {
"posts": null
},
"errors": [
{
"message": "Exclusive Start Key must have same size as table's key schema",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"posts"
],
"extensions": {
"code": "INTERNAL_SERVER_ERROR",
"exception": {
"message": "Exclusive Start Key must have same size as table's key schema",
"code": "ValidationException",
"time": "2018-07-31T21:20:11.286Z",
"requestId": "f8961dcd-325c-4cda-8fa8-855539cae715",
"statusCode": 400,
"retryable": false,
"stacktrace": [
"ValidationException: Exclusive Start Key must have same size as table's key schema",
" at Request.extractError (/home/node/node_modules/aws-sdk/lib/protocol/json.js:48:27)",
" at Request.callListeners (/home/node/node_modules/aws-sdk/lib/sequential_executor.js:105:20)",
" at Request.emit (/home/node/node_modules/aws-sdk/lib/sequential_executor.js:77:10)",
" at Request.emit (/home/node/node_modules/aws-sdk/lib/request.js:683:14)",
" at Request.transition (/home/node/node_modules/aws-sdk/lib/request.js:22:10)",
" at AcceptorStateMachine.runTo (/home/node/node_modules/aws-sdk/lib/state_machine.js:14:12)",
" at /home/node/node_modules/aws-sdk/lib/state_machine.js:26:10",
" at Request.<anonymous> (/home/node/node_modules/aws-sdk/lib/request.js:38:9)",
" at Request.<anonymous> (/home/node/node_modules/aws-sdk/lib/request.js:685:12)",
" at Request.callListeners (/home/node/node_modules/aws-sdk/lib/sequential_executor.js:115:18)"
]
}
}
}
]
}
Обновлено:
Вот что DynamoDB выводит в консоли:
dynamo-forum | Jul 31, 2018 9:32:31 PM com.almworks.sqlite4java.Internal log
dynamo-forum | WARNING: [sqlite] SQLiteDBAccess$20@268969a1: job exception
dynamo-forum | java.lang.NullPointerException
dynamo-forum | at com.amazonaws.services.dynamodbv2.local.shared.access.sqlite.SQLiteDBAccessUtils.translateKeyAttributeValue(SQLiteDBAccessUtils.java:194)
dynamo-forum | at com.amazonaws.services.dynamodbv2.local.shared.access.sqlite.SQLiteDBAccess$20.doWork(SQLiteDBAccess.java:2012)
dynamo-forum | at com.amazonaws.services.dynamodbv2.local.shared.access.sqlite.SQLiteDBAccess$20.doWork(SQLiteDBAccess.java:1787)
dynamo-forum | at com.amazonaws.services.dynamodbv2.local.shared.access.sqlite.AmazonDynamoDBOfflineSQLiteJob.job(AmazonDynamoDBOfflineSQLiteJob.java:97)
dynamo-forum | at com.almworks.sqlite4java.SQLiteJob.execute(SQLiteJob.java:372)
dynamo-forum | at com.almworks.sqlite4java.SQLiteQueue.executeJob(SQLiteQueue.java:534)
dynamo-forum | at com.almworks.sqlite4java.SQLiteQueue.queueFunction(SQLiteQueue.java:667)
dynamo-forum | at com.almworks.sqlite4java.SQLiteQueue.runQueue(SQLiteQueue.java:623)
dynamo-forum | at com.almworks.sqlite4java.SQLiteQueue.access$000(SQLiteQueue.java:77)
dynamo-forum | at com.almworks.sqlite4java.SQLiteQueue$1.run(SQLiteQueue.java:205)
dynamo-forum | at java.lang.Thread.run(Thread.java:748)
dynamo-forum |
И это от AWS-SDK с использованием пакета NPM:
service-forum | [AWS dynamodb 500 0.025s 0 retries] query({ TableName: 'forum-post',
service-forum | IndexName: 'parent_post_id-created_at-index',
service-forum | KeyConditionExpression: '#parent_post_id = :parent_post_id',
service-forum | FilterExpression: '#resource_id = :resource_id',
service-forum | ExpressionAttributeNames:
service-forum | { '#parent_post_id': 'parent_post_id',
service-forum | '#resource_id': 'resource_id' },
service-forum | ExpressionAttributeValues:
service-forum | { ':parent_post_id': { S: '-' },
service-forum | ':resource_id': { S: 'VALID_RESOURCE_ID' } },
service-forum | Limit: 5,
service-forum | ScanIndexForward: true,
service-forum | ExclusiveStartKey:
service-forum | { post_id: { S: '660b4878-e883-41ce-af4e-c393a20aac08' },
service-forum | created_at: { S: '2018-07-31T19:40:39.341Z' },
service-forum | parent_post_id: { S: '-' } }





Проблема заключается в KeySchema GlobalSecondaryIndex.
Вместо KeyType: 'SORT' должен быть KeyType: 'RANGE'
Документация AWS не очень помогает в этом, так как они всегда называют его sort key, но вы должны объявить тип как range.