Best way to make Amazon AWS DynamoDB queries using Swift?

后端 未结 1 1914
说谎
说谎 2020-12-07 23:50

I have recently implemented the AWS SDK for my iOS app, which I am developing in Swift. I have connected to my DB instance and am able to get a query response, however, I am

相关标签:
1条回答
  • 2020-12-08 00:20

    The easy answer to your question is : convert the JSON string returned into a Dictionary object. Something like this :

    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 {
                ...
            }
    

    However, I would strongly encourage you to look at the higher level DynamoDB mapper class When using DynamoDB mapper class, you define your data structure, and just give it to DynamoDB Mapper. Here is a full sample, from table creation to table deletion. The example inserts, removes, scans and query the table using DynamoDB Mapper.

    First, you need to initialise the client SDK

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

    This is a sample only. It is not a good practice to embed an Access Key and Secret Key in the code. Best practice would be to use the AWSCognitoCredentialsProvider instead (read more about Cognito).

    Define a class that maps your items in the table

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

    To create a table

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

    To delete a table

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

    To insert items

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

    To load one single item

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

    To query on hash and range key

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

    To scan items (full table scan)

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

    If you have no other usage of DynamoDB in US EAST 1, there is no cost associated with running this sample, as it is falling into DynamoDB's free tier.

    0 讨论(0)
提交回复
热议问题