2014-11-16 94 views
8

我最近爲我的iOS應用程序實施了AWS開發工具包,這是我在Swift中開發的。我已連接到我的數據庫實例並能夠獲得查詢響應,但是我正在努力將其轉換爲可用數據。我對Swift,AWS和一般編程相對陌生,所以可能會錯過一些明顯的東西!使用Swift製作Amazon AWS DynamoDB查詢的最佳方法?

我的代碼如下:

let atVal = AWSDynamoDBAttributeValue() 
    atVal.S = "123456abc" 
    let condition = AWSDynamoDBCondition() 
    condition.comparisonOperator = AWSDynamoDBComparisonOperator.EQ 
    condition.attributeValueList = [atVal] 

    let myDic: [String: AWSDynamoDBCondition] = ["userid": condition] 
    let query = AWSDynamoDBQueryInput() 
    query.indexName = "userid-index" 
    query.tableName = "users" 
    query.keyConditions = myDic 
    query.limit = 1 


    dynamoDB.query(query).continueWithBlock { 
     (task: BFTask!) -> AnyObject! in 
     let results = task.result as AWSDynamoDBQueryOutput 

     let myResults = results.items 
     println("object: \(myResults.description)") 

     return nil 
    } 

而對於此控制檯輸出是:

對象:[{ 面積= 「{\ n S = \」 西浦\「; \ N}「; name =「{\ n S = \」Olly Mayes \「; \ n}」; userid =「{\ n S = \」123456abc \「; \ n}」; }]

可以理解的是,使用AWS和Swift似乎沒有太多先例,所以任何幫助都將非常感謝!

回答

27

您的問題的簡單答案是:將返回的JSON字符串轉換爲Dictionary對象。 事情是這樣的:

let data = jsonDataItem.dataUsingEncoding(NSUTF8StringEncoding) 

    if data != nil { 
     var error : NSError? 
     let dict = NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.AllowFragments, error: &error) as? NSDictionary 

     if let e = error { 
      ... 
     } else { 
      ... 
     } 

不過,我會強烈建議您在較高水平DynamoDB映射類 看當使用DynamoDB映射器類,你定義的數據結構,只是給它DynamoDB Mapper。這是從表格創建到表格刪除的完整示例。該示例使用DynamoDB映射器插入,刪除,掃描和查詢表。

首先,您需要初始化客戶端SDK

let cp = AWSStaticCredentialsProvider(accessKey: "AK...", secretKey: "xxx") 
    let configuration = AWSServiceConfiguration(region: AWSRegionType.USEast1, credentialsProvider: cp) 
    AWSServiceManager.defaultServiceManager().setDefaultServiceConfiguration(configuration) 

這僅僅是一個樣品。在代碼中嵌入Access Key和Secret Key不是一個好習慣。最佳做法是使用AWSCognitoCredentialsProvider代替(read more about Cognito)。

定義你的項目映射表中的一類

class Item : AWSDynamoDBModel, AWSDynamoDBModeling { 

    var email : String = "" 
    var date : String = "" 
    var note : String = "" 
    var number : Double = 0.0 

    override init!() { super.init() } 

    required init!(coder: NSCoder!) { 
     fatalError("init(coder:) has not been implemented") 
    } 

    class func dynamoDBTableName() -> String! { 
     return "Demo" 
    } 
    class func hashKeyAttribute() -> String! { 
     return "email" 
    } 
    class func rangeKeyAttribute() -> String! { 
     return "date" 
    } 

    //required to let DynamoDB Mapper create instances of this class 
    override init(dictionary dictionaryValue: [NSObject : AnyObject]!, error: NSErrorPointer) { 
     super.init(dictionary: dictionaryValue, error: error) 
    } 

    //workaround to possible XCode 6.1 Bug : "Type NotificationAck" does not conform to protocol "NSObjectProtocol" 
    override func isEqual(anObject: AnyObject?) -> Bool { 
     return super.isEqual(anObject) 
    } } 

要創建一個表

self.createTable().continueWithSuccessBlock {(task: BFTask!) -> BFTask! in 
    NSLog("Create table - success") 
    return nil 
} 


func createTable() -> BFTask! { 
    let pt = AWSDynamoDBProvisionedThroughput() 
    pt.readCapacityUnits = 10 
    pt.writeCapacityUnits = 10 

    let emailAttr = AWSDynamoDBAttributeDefinition() 
    emailAttr.attributeName = "email" 
    emailAttr.attributeType = AWSDynamoDBScalarAttributeType.S 

    let dateAttr = AWSDynamoDBAttributeDefinition() 
    dateAttr.attributeName = "date" 
    dateAttr.attributeType = AWSDynamoDBScalarAttributeType.S 

    let emailKey = AWSDynamoDBKeySchemaElement() 
    emailKey.attributeName = "email" 
    emailKey.keyType = AWSDynamoDBKeyType.Hash 

    let dateKey = AWSDynamoDBKeySchemaElement() 
    dateKey.attributeName = "date" 
    dateKey.keyType = AWSDynamoDBKeyType.Range 

    let ct = AWSDynamoDBCreateTableInput() 
    ct.tableName = "Demo" 
    ct.provisionedThroughput = pt 
    ct.attributeDefinitions = [emailAttr, dateAttr] 
    ct.keySchema = [ emailKey, dateKey ] 

    NSLog("Creating table") 

    let client = AWSDynamoDB.defaultDynamoDB() 
    return client.createTable(ct) 
} 

要刪除表

self.deleteTable().continueWithSuccessBlock({ (task: BFTask!) -> BFTask! in 
    NSLog("Delete table - success") 
    return nil 
}) 

func deleteTable() -> BFTask! { 

    let dt = AWSDynamoDBDeleteTableInput() 
    dt.tableName = "Demo" 

    NSLog("Deleting table") 
    let client = AWSDynamoDB.defaultDynamoDB() 
    return client.deleteTable(dt) 
} 

插入項目

self.insertSomeItems().continueWithBlock({ 
    (task: BFTask!) -> BFTask! in 

    if (task.error != nil) { 
     NSLog(task.error.description) 
    } else { 
     NSLog("DynamoDB save succeeded") 
    } 

    return nil; 
}) 

func insertSomeItems() -> BFTask! { 
    let mapper = AWSDynamoDBObjectMapper.defaultDynamoDBObjectMapper() 

    var item = Item() 
    item.email = "[email protected]" 
    item.date = "20141101" 
    item.note = "This is item #1" 
    item.number = 1.0 
    let task1 = mapper.save(item) 

    item = Item() 
    item.email = "[email protected]" 
    item.date = "20141102" 
    item.note = "This is item #2" 
    item.number = 2.0 
    let task2 = mapper.save(item) 

    item = Item() 
    item.email = "[email protected]" 
    item.date = "20141103" 
    item.note = "This is item #3" 
    item.number = 3.0 
    let task3 = mapper.save(item) 

    return BFTask(forCompletionOfAllTasks: [task1, task2, task3]) 
} 

要加載一個單一項目

self.load("[email protected]", range:"20141101").continueWithSuccessBlock({ (task: BFTask!) -> BFTask! in 
    NSLog("Load one value - success") 
    let item = task.result as Item 
    print(item) 
    return nil 
}) 


func load(hash: String, range: String) -> BFTask! { 
    let mapper = AWSDynamoDBObjectMapper.defaultDynamoDBObjectMapper() 
    return mapper.load(Item.self, hashKey: hash, rangeKey: range) 

} 

要在哈希和範圍鍵

/* 
    keyConditions 
    http://docs.aws.amazon.com/AWSiOSSDK/latest/Classes/AWSDynamoDBQueryInput.html#//api/name/keyConditions 
*/ 
let cond = AWSDynamoDBCondition() 
let v1 = AWSDynamoDBAttributeValue(); v1.S = "20141101" 
cond.comparisonOperator = AWSDynamoDBComparisonOperator.EQ 
cond.attributeValueList = [ v1 ] 
let c = [ "date" : cond ] 
self.query("[email protected]", keyConditions:c).continueWithSuccessBlock({ (task: BFTask!) -> BFTask! in 
    NSLog("Query multiple values - success") 
    let results = task.result as AWSDynamoDBPaginatedOutput 
    for r in results.items { 
     print(r) 
    } 
    return nil 
}) 

func query(hash: String, keyConditions:[NSObject:AnyObject]) -> BFTask! { 
    let mapper = AWSDynamoDBObjectMapper.defaultDynamoDBObjectMapper() 

    let exp = AWSDynamoDBQueryExpression() 
    exp.hashKeyValues  = hash 
    exp.rangeKeyConditions = keyConditions 

    return mapper.query(Item.self, expression: exp) 
} 

要掃描的項目(完整的查詢表掃描)

let cond = AWSDynamoDBCondition() 
let v1 = AWSDynamoDBAttributeValue(); v1.S = "20141101" 
cond.comparisonOperator = AWSDynamoDBComparisonOperator.GT 
cond.attributeValueList = [ v1 ] 

let exp = AWSDynamoDBScanExpression() 
exp.scanFilter = [ "date" : cond ] 

self.scan(exp).continueWithSuccessBlock({ (task: BFTask!) -> BFTask! in 
    NSLog("Scan multiple values - success") 
    let results = task.result as AWSDynamoDBPaginatedOutput 
    for r in results.items { 
     print(r) 
    } 
    return nil 
}) 

func scan(expression : AWSDynamoDBScanExpression) -> BFTask! { 

    let mapper = AWSDynamoDBObjectMapper.defaultDynamoDBObjectMapper() 
    return mapper.scan(Item.self, expression: expression) 
} 

如果你有DynamoDB在美國東1沒有其他用途,不存在與運行這個樣本,因爲它是落入DynamoDB's free tier相關的成本。

+0

感謝您的回覆。我已經嘗試了兩種方法,並沒有設法得到我所追求的結果。第一個似乎失敗了,因爲返回的JSON實際上並不是一個正確形成的JSON。 如果可能的話,我想讓對象映射工作,你知道如果這個動作是'查詢'而不是'保存'會如何工作? 爲了清楚我想使用用戶ID字段查詢用戶表 - 這不是主要索引,它是一個二級索引 - 我想要取回該用戶的「區域」。 – ollym

+0

是的,你也可以使用映射器進行查詢。見http://docs.aws.amazon.com/AWSiOSSDK/latest/Classes/AWSDynamoDBObjectMapper.html#//api/name/query:expression:如果我今晚有時間,我會試着讓你成爲一個例子 –

+0

我已經試了幾次,沒有運氣!你認爲你可以展示一個簡單的例子嗎?當我回到我的開發機器時,我會粘貼我已經完成的任務... – ollym