DynamoDB Xcode6 Swift, используя три столбца в качестве ключа
Я пытаюсь использовать таблицу DynamoDB для хранения этих данных:
DartsPlayerInsultTable
CustomerId String
PlayerId String
PlayerInsult String
Используя метод (концепция, а не код), описанный здесь:
https://java.awsblog.com/post/Tx3GYZEVGO924K4/The-DynamoDBMapper-Local-Secondary-Indexes-and-You
Вот:
http://mobile.awsblog.com/post/TxTCW7KW8BGZAF/Amazon-DynamoDB-on-Mobile-Part-4-Local-Secondary-Indexes
и здесь:
http://labs.journwe.com/2013/12/15/dynamodb-secondary-indexes/comment-page-1/#comment-116
Я хочу иметь несколько записей об оскорблениях для каждого клиента-игрока. CustomerId - это мой хэш-ключ PlayerId - это мой ключ диапазона, и я пытаюсь использовать PlayerInsult в ключе, чтобы второе значение PlayerInsult вставляло вторую запись, а не заменяло существующую.
Для этого пытались использовать как глобальные, так и вторичные индексы, но если я попытаюсь добавить строку с новым оскорблением, она все равно заменит оскорбление тем же ключом "клиент-игрок", а не добавление нового.
Любые предложения о лучшем подходе для этого DynanoDB? Нужно ли создавать гибридную колонку для ключа диапазона? Пытаясь сохранить это простым...
class func createDartsPlayerInsultTable() -> BFTask {
let dynamoDB = AWSDynamoDB.defaultDynamoDB()
let hashKeyAttributeDefinition = AWSDynamoDBAttributeDefinition()
hashKeyAttributeDefinition.attributeName = "CustomerId"
hashKeyAttributeDefinition.attributeType = AWSDynamoDBScalarAttributeType.S
let hashKeySchemaElement = AWSDynamoDBKeySchemaElement()
hashKeySchemaElement.attributeName = "CustomerId"
hashKeySchemaElement.keyType = AWSDynamoDBKeyType.Hash
let rangeKeyAttributeDefinition = AWSDynamoDBAttributeDefinition()
rangeKeyAttributeDefinition.attributeName = "PlayerId"
rangeKeyAttributeDefinition.attributeType = AWSDynamoDBScalarAttributeType.S
let rangeKeySchemaElement = AWSDynamoDBKeySchemaElement()
rangeKeySchemaElement.attributeName = "PlayerId"
rangeKeySchemaElement.keyType = AWSDynamoDBKeyType.Range
/*
let indexRangeKeyAttributeDefinition = AWSDynamoDBAttributeDefinition()
indexRangeKeyAttributeDefinition.attributeName = "PlayerInsult"
indexRangeKeyAttributeDefinition.attributeType = AWSDynamoDBScalarAttributeType.S
let rangeKeySchemaElement = AWSDynamoDBKeySchemaElement()
rangeKeySchemaElement.attributeName = "PlayerId"
rangeKeySchemaElement.keyType = AWSDynamoDBKeyType.Range
let indexRangeKeyElement = AWSDynamoDBKeySchemaElement()
indexRangeKeyElement.attributeName = "PlayerInsult"
indexRangeKeyElement.keyType = AWSDynamoDBIndexRangeKeyType.
*/
//Add non-key attributes
let playerInsultAttrDef = AWSDynamoDBAttributeDefinition()
playerInsultAttrDef.attributeName = "PlayerInsult"
playerInsultAttrDef.attributeType = AWSDynamoDBScalarAttributeType.S
let provisionedThroughput = AWSDynamoDBProvisionedThroughput()
provisionedThroughput.readCapacityUnits = 5
provisionedThroughput.writeCapacityUnits = 5
// CREATE GLOBAL SECONDARY INDEX
/*
let gsi = AWSDynamoDBGlobalSecondaryIndex()
let gsiArray = NSMutableArray()
let gsiHashKeySchema = AWSDynamoDBKeySchemaElement()
gsiHashKeySchema.attributeName = "PlayerId"
gsiHashKeySchema.keyType = AWSDynamoDBKeyType.Hash
let gsiRangeKeySchema = AWSDynamoDBKeySchemaElement()
gsiRangeKeySchema.attributeName = "PlayerInsult"
gsiRangeKeySchema.keyType = AWSDynamoDBKeyType.Range
let gsiProjection = AWSDynamoDBProjection()
gsiProjection.projectionType = AWSDynamoDBProjectionType.All;
gsi.keySchema = [gsiHashKeySchema,gsiRangeKeySchema];
gsi.indexName = "PlayerInsult";
gsi.projection = gsiProjection;
gsi.provisionedThroughput = provisionedThroughput;
gsiArray .addObject(gsi)
*/
// CREATE LOCAL SECONDARY INDEX
let lsi = AWSDynamoDBLocalSecondaryIndex()
let lsiArray = NSMutableArray()
let lsiHashKeySchema = AWSDynamoDBKeySchemaElement()
lsiHashKeySchema.attributeName = "CustomerId"
lsiHashKeySchema.keyType = AWSDynamoDBKeyType.Hash
let lsiRangeKeySchema = AWSDynamoDBKeySchemaElement()
lsiRangeKeySchema.attributeName = "PlayerInsult"
lsiRangeKeySchema.keyType = AWSDynamoDBKeyType.Range
let lsiProjection = AWSDynamoDBProjection()
lsiProjection.projectionType = AWSDynamoDBProjectionType.All;
lsi.keySchema = [lsiHashKeySchema,lsiRangeKeySchema];
lsi.indexName = "PlayerInsult";
lsi.projection = lsiProjection;
//lsi.provisionedThroughput = provisionedThroughput;
lsiArray .addObject(lsi)
//Create TableInput
let createTableInput = AWSDynamoDBCreateTableInput()
createTableInput.tableName = DartsPlayerInsultTableName;
createTableInput.attributeDefinitions = [hashKeyAttributeDefinition, rangeKeyAttributeDefinition, playerInsultAttrDef]
//createTableInput.attributeDefinitions = [hashKeyAttributeDefinition, rangeKeyAttributeDefinition]
createTableInput.keySchema = [hashKeySchemaElement, rangeKeySchemaElement]
createTableInput.provisionedThroughput = provisionedThroughput
//createTableInput.globalSecondaryIndexes = gsiArray as [AnyObject]
createTableInput.localSecondaryIndexes = lsiArray as [AnyObject]
return dynamoDB.createTable(createTableInput).continueWithSuccessBlock({ (var task:BFTask!) -> AnyObject! in
if ((task.result) != nil) {
// Wait for up to 4 minutes until the table becomes ACTIVE.
let describeTableInput = AWSDynamoDBDescribeTableInput()
describeTableInput.tableName = DartsPlayerInsultTableName;
task = dynamoDB.describeTable(describeTableInput)
for var i = 0; i < 16; i++ {
task = task.continueWithSuccessBlock({ (task:BFTask!) -> AnyObject! in
let describeTableOutput:AWSDynamoDBDescribeTableOutput = task.result as! AWSDynamoDBDescribeTableOutput
let tableStatus = describeTableOutput.table.tableStatus
if tableStatus == AWSDynamoDBTableStatus.Active {
return task
}
sleep(15)
return dynamoDB .describeTable(describeTableInput)
})
}
}
return task
})
}
2 ответа
Положив это как ответ, а не как другой комментарий на случай, если он станет длинным...
Похоже, оскорбления среднего пользователя могут вписаться в одну запись. С отказом от ответственности, который я абсолютно ничего не знаю о swift, это может быть, по крайней мере, что-то относительно простое Сохраните ключи клиента и игрока. Прежде чем продолжать оскорбления, превратите весь список в одну большую строку, используя любую версию соединения ("|") swift. Когда вы извлекаете запись, выполните разделение ("|"), чтобы вернуть список. (Просто будьте осторожны с выбором разделителей, я использую только "|" в качестве примера, вы не хотите выбирать то, что может появиться в оскорблении...)
Там будет один пользователь с достаточным количеством оскорблений, чтобы взять вас за предел объекта 400 КБ. Установите константу максимального размера списка в своем коде - когда вы превращаете свои списки в строки, чтобы сохранить их в динамическом режиме, проверьте длину списка игроков по этому пределу. Если вы превысите его, разбейте свой список на куски такого размера и используйте ключи хеша и диапазона, такие как ("foo", "bar"), ("foo", "bar1"), ("foo", "bar2"), и т.д. Да, первый не имеет номер корзины в конце...
Когда вы запрашиваете данные, сначала просто выполните прямой запрос и предположите, что вы будете в хорошем случае (только "foo" и "bar", никаких других блоков). Когда вы распаковываете этот первый список, проверьте его длину. Если она равна вашей константе максимального размера списка, вы знаете, что у вас "плохой" пользователь и вам нужно выполнить запрос диапазона. Второй может использовать хеш-ключ "foo" и диапазон от "bar" до "bar9999". Вы получите все эти сегменты с этим запросом диапазона. Распакуйте и объедините все списки.
Это немного страшно, но в конечном итоге это должно быть прямо вперед для написания кода. Надеюсь, это все еще достаточно просто, чтобы подключиться к шаблонам, которые вы упоминали.
Я решил создать обычную таблицу Dynamodb с одним хеш-ключом, но новый хеш-ключ представляет собой комбинированную строку:
CustomerId + "|" + PlayerId
Не слишком сложно поддерживать синхронность между игроками и столами оскорблений, потому что как только игрок вставлен в стол игрока, изменение имени игрока приводит к вставке новой строки. Таким образом, оскорбления не нужно изменять, если имя игрока меняется. Вам нужно только убрать оскорбления, если игрок удален.
Такое поведение при обновлении работает именно так, как работает Dynamodb, если вы зададите для Player имя хеш-ключа, что я и сделал, чтобы убедиться, что они уникальны.