2014-11-16 2 views
8

Ho recentemente implementato l'SDK AWS per la mia app iOS, che sto sviluppando in Swift. Mi sono collegato al mio annuncio di istanza DB sono in grado di ottenere una risposta alla query, tuttavia sto facendo fatica a convertirlo in dati utilizzabili. Sono relativamente nuovo a Swift, AWS e programmazione in generale, quindi potrebbe mancare qualcosa di ovvio!Il modo migliore per eseguire query Amazon AWS DynamoDB utilizzando Swift?

Il mio codice è il seguente:

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 
    } 

E l'uscita della console per questo è:

oggetto: [{ zona = "{\ n S = \" West Hampstead \ "; \ n} "; name = "{\ n S = \" Olly Mayes \ "; \ n}"; userid = "{\ n S = \" 123456abc \ "; \ n}"; }

Non sembra esserci molta precedenza per l'utilizzo di AWS e Swift, comprensibilmente, quindi qualsiasi aiuto sarebbe molto apprezzato!

risposta

27

La risposta facile alla tua domanda è: convertire la stringa JSON restituita in un oggetto Dizionario. Qualcosa di simile a questo:

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

Tuttavia, vorrei vivamente di guardare il più alto livello di DynamoDB classe mapper Quando si utilizza DynamoDB classe mapper, è possibile definire la struttura dei dati, e solo dare a DynamoDB Mapper. Ecco un esempio completo, dalla creazione della tabella alla cancellazione della tabella. L'esempio inserisce, rimuove, scansiona e interroga la tabella utilizzando DynamoDB Mapper.

In primo luogo, è necessario inizializzare l'SDK client

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

Questo è solo un esempio. Non è una buona pratica incorporare una chiave di accesso e una chiave segreta nel codice. La migliore pratica sarebbe quella di utilizzare lo AWSCognitoCredentialsProvider invece (read more about Cognito).

Definire una classe che mappa i tuoi articoli nella tabella

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

per creare una tabella

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

per eliminare una tabella

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

Per inserire elementi

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

Per caricare un singolo elemento

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) 

} 

Per eseguire query su hash e la gamma chiave

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

Per eseguire la scansione articoli (completo scansione tabella)

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

Se non avete altro uso DynamoDB negli Stati Uniti EST 1, non v'è alcun costo associato a eseguire questo esempio, come si sta cadendo in DynamoDB's free tier.

+0

Grazie per la risposta. Ho provato entrambi i metodi e non sono riuscito a ottenere il risultato che sto cercando. Il primo sembra fallire perché il JSON restituito non è in realtà un JSON correttamente formato. Mi piacerebbe far funzionare l'oggetto mapper se possibile, sai come funzionerebbe se l'azione fosse "query" invece di "salva"? Per essere chiari mi piacerebbe interrogare la tabella degli utenti usando il campo userid - questo non è l'indice primario, è un indice secondario - e vorrei recuperare l''area' per questo utente. – ollym

+0

Sì, è possibile eseguire query utilizzando anche il mapper. Vedi http://docs.aws.amazon.com/AWSiOSSDK/latest/Classes/AWSDynamoDBObjectMapper.html#//api/name/query:expression: cercherò di farti un esempio se avessi tempo stasera –

+0

Ho provato questo alcune volte e senza fortuna! Pensi di poter mostrare un semplice esempio? Incollo ciò che ho già fatto quando torno alla mia macchina di sviluppo ... – ollym