【问题标题】:Best way to make Amazon AWS DynamoDB queries using Swift?使用 Swift 进行 Amazon AWS DynamoDB 查询的最佳方式?
【发布时间】:2020-04-07 03:45:53
【问题描述】:

我最近为我使用 Swift 开发的 iOS 应用程序实现了 AWS 开发工具包。我已连接到我的数据库实例并且能够获得查询响应,但是,我正在努力将其转换为可用数据。我对 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}"; 用户 ID = " {\n S = \"123456abc\";\n}"; }]

使用 AWS 和 Swift 似乎没有太多优先级,这是可以理解的,因此非常感谢任何帮助!

【问题讨论】:

    标签: amazon-web-services swift amazon-dynamodb


    【解决方案1】:

    您的问题的简单答案是:将返回的 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 Mapper 插入、删除、扫描和查询表。

    首先需要初始化客户端SDK

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

    这只是一个示例。在代码中嵌入访问密钥和秘密密钥不是一个好习惯。最佳做法是改用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  = "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)
    }
    

    扫描项目(全表扫描)

    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)
    }
    

    如果您在美国东部 1 地区没有其他 DynamoDB 用途,则运行此示例不会产生任何成本,因为它属于 DynamoDB's free tier

    【讨论】:

    • 感谢您的回复。我已经尝试了这两种方法,但都没有得到我想要的结果。第一个似乎失败了,因为返回的 JSON 实际上不是格式正确的 JSON。如果可能的话,我想让对象映射器工作,你知道如果操作是“查询”而不是“保存”,这将如何工作吗?为了清楚起见,我想使用 userid 字段查询 users 表 - 这不是主索引,它是辅助索引 - 我想取回该用户的“区域”。
    • 是的,您也可以使用映射器进行查询。见docs.aws.amazon.com/AWSiOSSDK/latest/Classes/…:今晚有空的话,我会努力给你举个例子
    • 我已经尝试了几次,但没有成功!你认为你可以举一个简单的例子吗?当我回到我的开发机器时,我将粘贴我已经完成的工作......
    • 这是一个纯 SWIFT 错误,而不是 AWS 错误。这是因为您的 task.result 不包含值...您的表中有项目“156”吗?为避免该运行时错误,请使用条件转换:let item = task.result as? DBItem(注意问号)
    • 我写了一个关于使用 AWS(包括 DynamoDB)作为 Swift 应用程序后端的教程系列。 peterfennema.nl/exploring-aws-as-a-backend-for-a-swift-app-1
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-01-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多