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 имя хеш-ключа, что я и сделал, чтобы убедиться, что они уникальны.

Другие вопросы по тегам