Amazon web services 使用Swift进行Amazon AWS DynamoDB查询的最佳方法?

Amazon web services 使用Swift进行Amazon AWS DynamoDB查询的最佳方法?,amazon-web-services,swift,amazon-dynamodb,Amazon Web Services,Swift,Amazon Dynamodb,我最近为我的iOS应用程序实现了AWS SDK,我正在Swift中开发。我已经连接到我的DB实例,并且能够获得查询响应,但是,我正在努力将其转换为可用数据。我对Swift、AWS和编程都比较陌生,所以可能遗漏了一些明显的东西 我的代码如下: let atVal = AWSDynamoDBAttributeValue() atVal.S = "123456abc" let condition = AWSDynamoDBCondition() condition.co

我最近为我的iOS应用程序实现了AWS SDK,我正在Swift中开发。我已经连接到我的DB实例,并且能够获得查询响应,但是,我正在努力将其转换为可用数据。我对Swift、AWS和编程都比较陌生,所以可能遗漏了一些明显的东西

我的代码如下:

    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
    }
此操作的控制台输出为:

对象:[{ area=“{\n S=\”西汉普斯特德\“;\n}”; name=“{\n S=\“Olly Mayes\”;\n}”; userid=“{\n S=\”123456abc\”;\n}”; }]


可以理解的是,使用AWS和Swift似乎没有太多的优先权,所以任何帮助都将不胜感激

问题的简单答案是:将返回的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 mapper类 当使用dynamodbmapper类时,您可以定义数据结构,并将其提供给。这是一个完整的示例,从表创建到表删除。该示例使用DynamoDB映射器插入、删除、扫描和查询表

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

    let cp = AWSStaticCredentialsProvider(accessKey: "AK...", secretKey: "xxx")
    let configuration = AWSServiceConfiguration(region: AWSRegionType.USEast1, credentialsProvider: cp)
    AWSServiceManager.defaultServiceManager().setDefaultServiceConfiguration(configuration)
这只是一个样品。在代码中嵌入访问密钥和密钥不是一个好的做法。最佳做法是改用()

定义映射表中项目的类

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)
}
创建表格

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)
}
删除表格

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  = "stormacq@amazon.com"
    item.date   = "20141101"
    item.note   = "This is item #1"
    item.number = 1.0
    let task1 = mapper.save(item)

    item = Item()
    item.email  = "stormacq@amazon.com"
    item.date   = "20141102"
    item.note   = "This is item #2"
    item.number = 2.0
    let task2 = mapper.save(item)

    item = Item()
    item.email  = "stormacq@amazon.lu"
    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("stormacq@amazon.com", 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("stormacq@amazon.com", 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)
}
扫描项目(全表扫描)


如果您在美国东部1没有其他使用DynamoDB,则运行此示例不会产生任何相关费用,因为它将陷入困境。

感谢您的回复。我两种方法都试过了,但都没有达到我想要的效果。第一个似乎失败了,因为返回的JSON实际上不是格式正确的JSON。如果可能的话,我想让对象映射器工作,你知道如果操作是“查询”而不是“保存”,这将如何工作吗?为了清楚起见,我想使用userid字段查询users表-这不是主索引,而是辅助索引-我想获取此用户的“区域”。是的,您也可以使用映射器进行查询。看:如果我今晚有时间,我会给你举个例子的。我已经试过几次了,但是运气不好!你能举个简单的例子吗?当我回到我的开发机器时,我将粘贴我已经完成的工作…这是一个纯粹的SWIFT错误,而不是AWS错误。这是因为您的task.result不包含值。。。你们桌上有“156”项吗?要避免该运行时错误,请使用条件转换:let item=task.result as?DBItem(请注意问号)我已经编写了一个关于使用AWS(包括DynamoDB)作为Swift应用程序后端的系列教程。