1
votes

Thanks in advance for any help. I am trying to get Batch items (Load multiple) items from one DynamoDb table using the AWS iOS SDK (Swift). I can load one item using the Block syntax, but I need to load 10 or more than that. I don't want to use 10 Block calls to load them individually. I tried to follow the attach stackoverflow Link (where the similar solution is given) but I am getting the following compiler error message. I come from Java background, hence could also be a syntax issue. Is it the right way to load multiple items? I don't want to use low level API. Any help, where I am going wrong. Thanks.

AnyObject? is not convertible to Any?

aws dynamodb how to use object mapper with batch get in ios

let dynamoDBObjectMapper = AWSDynamoDBObjectMapper.default()
    var tasksList = Array<AWSTask<AnyObject>>()
    for i in 1...10 {
         tasksList.append(dynamoDBObjectMapper.load(AWSCards.self, hashKey: "SH_"+String(i), rangeKey: nil))
    }

     AWSTask.init(forCompletionOfAllTasksWithResults: tasksList).continueWithBlock { (task) -> AnyObject? in
     if let cards = task.result as? [AWSCards] {
      print(cards.count)
         }
     else if let error = task.error {
     print(error.localizedDescription)
       }
     return nil
 }
2

2 Answers

0
votes

Have a try with the following codes (Swift 4.1, Feb 9th, 2018):

let dynamoDBObjectMapper = AWSDynamoDBObjectMapper.default()
        var tasksList = Array<AWSTask<AnyObject>>()
        for i in 1...10 {

             tasksList.append(dynamoDBObjectMapper.load(AWSCards.self, hashKey: "SH_"+String(i), rangeKey: nil))
        }

        AWSTask<AnyObject>.init(forCompletionOfAllTasksWithResults: tasksList).continueWith { (task) -> Any? in
                        if let cards = task.result as? [AWSCards] {
                            print(cards.count)
                        }
                        else if let error = task.error {
                            print(error.localizedDescription)
                        }
                        return nil
                }
0
votes

Your question is "how to use the object mapper" but it might be more efficient for you to not use it.

However, there is a way to use it. See Niklas's answer here and here (he copy & pasted), but something about it strikes me as fishy. I want to make the assertion that it is not as fast as the built-in batch-get function, but I am unsure. I suspect that this does not complete the items in parallel, or at least not as efficiently as in BatchGetItem.

See the docs: "In order to minimize response latency, BatchGetItem retrieves items in parallel."

According to Yosuke, "Currently, AWSDynamoDBObjectMapper does not support the batch get item. You need to load one item at a time if you want to use the object mapper" as of 2016. This still seems to be the case. I am using a version a couple versions behind, but not too far behind. Someone check.

In conclusion, if you are loading one item at a time, you are likely missing out on the whole purpose of BatchGetItem (low latency).

Pulling from various sources, including John Davis's question here, I have tested and ran this BatchGetItem result. Here ya go.

import AWSDynamoDB

let primaryKeyToSortKeyDict : [String : String] = .... // Your stuff

var keys = [Any]()

for key in primaryKeyToSortKeyDict.keys {
    let partitionKeyValue = AWSDynamoDBAttributeValue()
    partitionKeyValue?.s = String(key)
    let sortValue = AWSDynamoDBAttributeValue()
    sortValue?.s = String(primaryKeyToSortKeyDict[key]!)
    keys.append(["partitionKeyAttributeName": partitionKeyValue, "sortKeyAttributeName": sortValue])
}

let keysAndAttributesMap = AWSDynamoDBKeysAndAttributes()
keysAndAttributesMap?.keys = keys as? [[String : AWSDynamoDBAttributeValue]]
keysAndAttributesMap?.consistentRead = true
let tableMap = [table : keysAndAttributesMap]

let request = AWSDynamoDBBatchGetItemInput()
request?.requestItems = tableMap as? [String : AWSDynamoDBKeysAndAttributes]
request?.returnConsumedCapacity = AWSDynamoDBReturnConsumedCapacity.total

guard request != nil else {
    print("Handle some error")
    return
}

AWSDynamoDB.default().batchGetItem(request!) { (output, error) in
    print("Here is the batchgetitem output")
    if error == nil {
        // do output stuff
    } else {
        // handle error
    }
}